-3

I have array of hash :

[
  {:name=>"King Summer", :number=>"0034242342"}, 
  {:name=>"Max Snow", :number=>"899899080"}, 
  {:name=>"Duck Doe", :number=>"90897688"}, 
  {:name=>"Shark Jon", :number=>"0034242342"}
]

At the above, the value of key :number {:name=>"King Summer", :number=>"0034242342"} duplicated with {:name=>"Shark Jon", :number=>"0034242342"}

How to find the duplicate :number and showing output like this in console :

=== List with duplicate number ===
King Summer – 0034242342 : ok
Max Snow – 899899080 : ok
Duck Doe – 90897688 : ok
Shark Jon – 0034242342 : duplicate number

== List without duplicate number ===
1 - King Summer – 0034242342
2 - Max Snow – 899899080
3 - Duck Doe – 90897688
spn
  • 85
  • 1
  • 8
  • 3
    What have you tried and what exactly is the problem with it? – jonrsharpe Feb 21 '19 at 08:22
  • Possible duplicate of [Ruby: How to find and return a duplicate value in array?](https://stackoverflow.com/questions/8921999/ruby-how-to-find-and-return-a-duplicate-value-in-array) – Xero Feb 21 '19 at 08:27

3 Answers3

2

You can simply add status using inject where inject's accumulator will hold numbers passed in previous iterations,

arr.inject([]) { |m,a| m.include?(a[:number]) ? (a[:status] = 'duplicated number') : ((m << a[:number]) && (a[:status] = 'ok')); m} 

arr
# [
#  {:name=>"King Summer", :number=>"0034242342", :status=>"ok"}, 
#  {:name=>"Max Snow", :number=>"899899080", :status=>"ok"}, 
#  {:name=>"Duck Doe", :number=>"90897688", :status=>"ok"}, 
#  {:name=>"Shark Jon", :number=>"0034242342", :status=>"duplicated number"}
# ]

Iterate your this data using each later.

ray
  • 5,454
  • 1
  • 18
  • 40
  • Thank you, but `duplicated number` status not added, all statu s`ok`. I've try in irb: irb(main):011:0> arr.inject([]) { |m,a| a.include?(a[:number]) ? (a[:status] = 'duplicated number') : ((m << a[:number]) && (a[:status] = 'ok')); m} => ["0034242342", "899899080", "90897688", "0034242342"] irb(main):012:0> arr => [{:name=>"King Summer", :number=>"0034242342", :status=>"ok"}, {:name=>"Max Snow", :number=>"899899080", :status=>"ok"}, {:name=>"Duck Doe", :number=>"90897688", :status=>"ok"}, {:name=>"Shark Jon", :number=>"0034242342", :status=>"ok"}] – spn Feb 21 '19 at 09:18
  • @spn Sorry there was minor correction as `m.include?` was needed instead of `a.include?`. Please check updated answer – ray Feb 21 '19 at 10:33
  • Thanks! Note that existing array is updated here, accept if it work around for you – ray Feb 21 '19 at 10:41
0

You can do this way. Maybe not the cleanest way.

duplicated = []
non_duplicated = []

array = [
  {:name=>"King Summer", :number=>"0034242342"}, 
  {:name=>"Max Snow", :number=>"899899080"}, 
  {:name=>"Duck Doe", :number=>"90897688"}, 
  {:name=>"Shark Jon", :number=>"0034242342"}
]

array.each do |a| 

  is_duplicated = non_duplicated.find do |i|
    i == a[:number]
  end

  if is_duplicated
    duplicated.push(a[:number])
    non_duplicated.delete(a[:number])
    next
  end

  non_duplicated.push(a[:number])

end

Edit

Alternative

array.partition do |value|
  number = value[:number]

  array.map do |i|
    i[:number]
  end.count(number) > 1
end

This will return an array with 2 parts (duplicated, and the rest) :

[
  [
    {:name=>"King Summer", :number=>"0034242342"}, 
    {:name=>"Shark Jon", :number=>"0034242342"}
  ], 
  [
    {:name=>"Max Snow", :number=>"899899080"},
    {:name=>"Duck Doe", :number=>"90897688"}
  ]
]
Xero
  • 3,951
  • 4
  • 41
  • 73
  • 1
    Better to use [`partition`](https://apidock.com/ruby/Enumerable/partition) if you're assigning to two arrays in this manner :) – SRack Feb 22 '19 at 09:03
  • 1
    @SRack thank you for your feedback :), i didnt know this way. I will update my answer – Xero Feb 22 '19 at 09:27
0

Other option is building a hash which groups duplicated (true) and not (false).

Given the array:

ary = [
        {name: "King Summer", number: "0034242342"}, 
        {name: "Max Snow", number: "899899080"}, 
        {name: "Duck Doe", number: "90897688"}, 
        {name: "Shark Jon", number: "0034242342"},
        {name: "Jim Kirk", number: "90897688"},
        {name: "Mr. Spock", number: "10897688"}
      ]

Build the hash:

res = ary.group_by { |h| h[:number] }.group_by { |_,v| v.size > 1 }.transform_values(&:to_h)

#=> {true=>{"0034242342"=>[{:name=>"King Summer", :number=>"0034242342"}, {:name=>"Shark Jon", :number=>"0034242342"}], "90897688"=>[{:name=>"Duck Doe", :number=>"90897688"}, {:name=>"Jim Kirk", :number=>"90897688"}]}, false=>{"899899080"=>[{:name=>"Max Snow", :number=>"899899080"}], "10897688"=>[{:name=>"Mr. Spock", :number=>"10897688"}]}}

Then list the duplicated:

res[true].each do |number, people|
  puts "- ph. number: #{number}"
  people.each { |person| puts "\t"*2 + person[:name] }
end

# - ph. number: 0034242342
#     King Summer
#     Shark Jon
# - ph. number: 90897688
#     Duck Doe
#     Jim Kirk


Or
res.each do |_, list|
  puts "-"*10
  list.each do |number, people|
    puts "- ph. number: #{number}"
    people.each { |person| puts "\t"*2 + person[:name] }
  end
end

# ----------
# - ph. number: 0034242342
#     King Summer
#     Shark Jon
# - ph. number: 90897688
#     Duck Doe
#     Jim Kirk
# ----------
# - ph. number: 899899080
#     Max Snow
# - ph. number: 10897688
#     Mr. Spock
iGian
  • 11,023
  • 3
  • 21
  • 36