Identify repeating elements within a two-dimensional array

Asked

Viewed 1,356 times

2

In an array

a = [[1,"José"],[2,"Pedro"],[3,"Maria"],[4,"Lauro"],[2,"Pedro"],
     [5,"Léo"],[1,"José"],[6,"Caio"]]

how to get a new array b that shows the positions of the indices with the repeating (equal) arrays? , in which case the array b would look like this:

b = [[0,6],[1,4]]

I was able to make a clone of the array by comparing each position, but it was somewhat time-consuming and it also has the original positions that are included in array b making it the same array with the same positions, so it wasn’t cool.

  • Show what you’ve done.

  • So it works, I’m trying to take the addiction of the for to use each that is more elegant and functional, I’ve changed several codes replacing the for, mainly because of the indexes that I get lost with them a lot. 'a1 = a.clone b = Array.new cont_i = 0 for i in (0..a.length-1) for j in ((i+1)..a1.length-1) if a[i] == a1[j] b[cont_i] = [i, j] cont_i += 1 end&end end&#;'

2 answers

3


There are many ways to do this, but according to this benchmark, this is the most efficient solution:

a = [[1,"José"],[2,"Pedro"],[3,"Maria"],[4,"Lauro"],[2,"Pedro"],
 [5,"Léo"],[1,"José"],[6,"Caio"]]

dups = {}
a.each_with_index do |val, idx|
    (dups[val] ||= []) << idx
end
dups.delete_if {|k,v| v.size == 1}

# => {[1, "José"]=>[0, 6], [2, "Pedro"]=>[1, 4]}
  • I liked the use of hash, no doubt there are several ways to do this, ranging from the experience of each programmer, which is not my case.. rsrs, but I’m learning from these masters here.

  • Rafael, I was impressed with the speed with which the result appears, in the tests I did, in many executions does not reach the time of 1(one) second, it is instantaneous, already in my solution(Aff) and in Guilherme, reaches 9 seconds, why does this occur? is the fact of using hash? would someone explain to me? Note: The array I am testing has 3501 arrays.

1

a = [[1,"José"],[2,"Pedro"],[3,"Maria"],[4,"Lauro"],[2,"Pedro"],
     [5,"Léo"],[1,"José"],[6,"Caio"]]

Walking through the arrays methods we can assemble the following:

each_index iterate over the indexes. To know which indexes are equal to a given element we can do the following:

a.each_index.select{|i| a[i] == [1,"José"] }
# => [0, 6]

If you want to apply this to all array elements, use it first uniq to generate a list without repetitions and then the map to transform each element in its contents:

a.uniq.map{|el| a.each_index.select{|i| a[i] == el } }
# => [[0, 6], [1, 4], [2], [3], [5], [7]]

If you want to show only those that there is some repetition, reject at the end everything that only exists once:

a.uniq.map{|el| a.each_index.select{|i| a[i] == el } }.reject{|is| is.size == 1 }
# => [[0, 6], [1, 4]]

Elegant, not?

  • And very elegant.. Cool is this nesting of methods that I need to focus on more.

Browser other questions tagged

You are not signed in. Login or sign up in order to post.