How can I create an array of duplicate case insensitive strings from another array in Ruby?

I have an array of strings. I want to change the name of these duplicate lines to add a numeric value to make them the same ...

Original array

a, a, A, b, c, D, d

      

Corrected array

a, a1, A2, b, c, D, d1

      

I approached this with the following code; however, if the strings are a different case structure, then they are not currently considered duplicates with this piece of code. I would like them to be considered duplicates, but not change their case in the result array.

duplicate_counter = 1
duplicates = Array.new
duplicates = file_columns.select{ |e| file_columns.count(e) > 1 } # get duplicate column names

duplicates.each{ |x| file_columns.delete(x) }
duplicates.sort!
duplicates.each_with_index do |d, i|

  if i > 0
     if d == duplicates[i-1]
        d = d.strip + duplicate_count.to_s
        duplicate_count += 1
     else 
        duplicate_count = 1
     end
  end

  # Add back the column names, but with the appended numerical counts to make them unique
  file_columns.push(d)
end

      

+3


source to share


2 answers


You have thought too much about it. I'm sure there are better ways to do this, but it gets the job done.



a = ['a', 'a', 'A', 'b', 'c', 'D', 'd']
letters = Hash.new(-1)
a.map do |letter|
  l = letter.downcase
  letters[l] += 1
  if (letters[l] > 0)
    "#{letter}#{letters[l]}"
  else
    "#{letter}"
  end
end

      

+3


source


This can be done here if the case-independent letters are not necessarily grouped. For example, it will convert this array:

arr = %w{ a D a A b c D a d }
  #=> ["a", "D", "a", "A", "b", "c", "D", "a", "d"]

      

in

["a", "D", "a1", "A2", "b", "c", "D1", "a3", "d2"]

      

code

def convert(arr)
  arr.each_with_index
     .group_by { |c,_| c.downcase }
     .values
     .flat_map { |c|
       c.map
        .with_index { |(f,l),i| [i > 0 ? f<<i.to_s : f, l] } }
     .sort_by(&:last)
     .map(&:first)
end

      

Example



For arr

above:

convert(arr)
 #=> ["a", "D", "a1", "A2", "b", "c", "D1", "a3", "d2"]

      

Explanation

Dear reader, if you are new to Ruby, this can seem incredibly difficult. However, if you break it down into steps, it's not that bad. Once you have gained experience and familiarity with the generally accepted methods, it will be quite natural. Here I have used the following methods chained together so that the return value of each becomes the receiver of the following:

Here's what's going on.

enum = arr.each_with_index
  #=> #<Enumerator: ["a", "D", "a", "A", "b", "c",
  #                  "D", "a", "d"]:each_with_index>
h = enum.group_by { |c,_| c.downcase }
  #=> {"a"=>[["a", 0], ["a", 2], ["A", 3], ["a", 7]],
  #    "d"=>[["D", 1], ["D", 6], ["d", 8]],
  #    "b"=>[["b", 4]],
  #    "c"=>[["c", 5]]}
a = h.values
  #=> [[["a", 0], ["a", 2], ["A", 3], ["a", 7]],
  #    [["D", 1], ["D", 6], ["d", 8]],
  #    [["b", 4]],
  #    [["c", 5]]]
b = a.flat_map { |c| c.map.with_index { |(f,l),i| [i > 0 ? f<<i.to_s : f, l] } }
  #=> [["a", 0], ["a1", 2], ["A2", 3], ["a3", 7], ["D", 1],
  #    ["D1", 6], ["d2", 8], ["b", 4], ["c", 5]]
c = b.sort_by(&:last)
  #=> [["a", 0], ["D", 1], ["a1", 2], ["A2", 3], ["b", 4],
  #    ["c", 5], ["D1", 6], ["a3", 7], ["d2", 8]]
c.map(&:first)
  #=> ["a", "D", "a1", "A2", "b", "c", "D1", "a3", "d2"]

      

+1


source







All Articles