Reputation: 347
I have an array like this:
[1, 2, 3, 3, 4, 4, 5, 6, 6, 6, 7]
I want to know if there's a method to get this:
[[1, 2, 3, 4, 5, 6, 7], [3, 4, 6], [6]]
I know there is Array.uniq
but this removes the duplicate elements, and I would like to keep them.
Upvotes: 0
Views: 553
Reputation: 110675
Here are a couple of ways of doing it.
arr = [1, 2, 3, 3, 4, 4, 5, 6, 6, 6, 7]
#1
b = []
a = arr.dup
while a.any?
u = a.uniq
b << u
a = a.difference u
end
b
#=> [[1, 2, 3, 4, 5, 6, 7], [3, 4, 6], [6]]
The helper Array#difference
is defined in my answer here.
#2
arr.map { |n| [n, arr.count(n)] }
.each_with_object({}) { |(n,cnt),h|
(1..cnt).each { |i| (h[i] ||= []) << n } }
.values
.map(&:uniq)
#=> [[1, 2, 3, 4, 5, 6, 7], [3, 4, 6], [6]]
The steps, for:
arr = [1, 2, 3, 3, 6, 6, 6, 7]
a = arr.map { |n| [n, arr.count(n)] }
#=> [[1, 1], [2, 1], [3, 2], [3, 2], [4, 2], [4, 2],
# [5, 1], [6, 3], [6, 3], [6, 3], [7, 1]]
enum = a.each_with_object({})
#=> #<Enumerator: [[1, 1], [2, 1], [3, 2], [3, 2], [4, 2], [4, 2],
# [5, 1], [6, 3], [6, 3], [6, 3], [7, 1]]:each_with_object({})>
To view the elements of enum
:
enum.to_a
#=> [[[1, 1], {}], [[2, 1], {}],...[[7, 1], {}]]
Now step through the enumerator and examine the hash after each step:
(n,cnt),h = enum.next
#=> [[1, 1], {}]
n #=> 1
cnt #=> 1
h #=> {}
(1..cnt).each { |i| (h[i] ||= []) << n }
h #=> {1=>[1]}
(n,cnt),h = enum.next
#=> [[2, 1], {1=>[1]}]
(1..cnt).each { |i| (h[i] ||= []) << n }
h #=> {1=>[1, 2]}
(n,cnt),h = enum.next
#=> [[3, 2], {1=>[1, 2]}]
(1..cnt).each { |i| (h[i] ||= []) << n }
h #=> {1=>[1, 2, 3], 2=>[3]}
(n,cnt),h = enum.next
#=> [[3, 2], {1=>[1, 2, 3], 2=>[3]}]
(1..cnt).each { |i| (h[i] ||= []) << n }
h #=> {1=>[1, 2, 3, 3], 2=>[3, 3]}
(n,cnt),h = enum.next
#=> [[6, 3], {1=>[1, 2, 3, 3], 2=>[3, 3]}]
(1..cnt).each { |i| (h[i] ||= []) << n }
h #=> {1=>[1, 2, 3, 3, 6], 2=>[3, 3, 6], 3=>[6]}
(n,cnt),h = enum.next
#=> [[6, 3], {1=>[1, 2, 3, 3, 6], 2=>[3, 3, 6], 3=>[6]}]
(1..cnt).each { |i| (h[i] ||= []) << n }
h #=> {1=>[1, 2, 3, 3, 6, 6], 2=>[3, 3, 6, 6], 3=>[6, 6]}
(n,cnt),h = enum.next
#=> [[6, 3], {1=>[1, 2, 3, 3, 6, 6], 2=>[3, 3, 6, 6], 3=>[6, 6]}]
(1..cnt).each { |i| (h[i] ||= []) << n }
h #=> {1=>[1, 2, 3, 3, 6, 6, 6], 2=>[3, 3, 6, 6, 6], 3=>[6, 6, 6]}
(n,cnt),h = enum.next
#=> [[7, 1], {1=>[1, 2, 3, 3, 6, 6, 6], 2=>[3, 3, 6, 6, 6], 3=>[6, 6, 6]}]
(1..cnt).each { |i| (h[i] ||= []) << n }
h #=> {1=>[1, 2, 3, 3, 6, 6, 6, 7], 2=>[3, 3, 6, 6, 6], 3=>[6, 6, 6]}
Lastly, extract and uniqify the values of the hash:
b = h.values
#=> [[1, 2, 3, 3, 6, 6, 6, 7], [3, 3, 6, 6, 6], [6, 6, 6]]
b.map(&:uniq)
#=> [[1, 2, 3, 6, 7], [3, 6], [6]]
Upvotes: 0
Reputation: 631
On ruby you could add a method to the class Array
. Like this:
class Array
def uniqA (acc)
return acc if self.empty?
# return self.replace acc if self.empty? #to change the object itself
acc << self.uniq
self.uniq.each { |x| self.delete_at(self.index(x)) }
uniqA(acc)
end
end
b = [1, 2, 3, 3, 4, 4, 5, 6, 6, 6, 7]
print b.uniqA([])
#=> [[1, 2, 3, 4, 5, 6, 7], [3, 4, 6], [6]]
print b
#=> []
Or you could do this, to keep the elements on b
:
b = b.uniqA([])
#=> [[1, 2, 3, 4, 5, 6, 7], [3, 4, 6], [6]]
print b
#=> [[1, 2, 3, 4, 5, 6, 7], [3, 4, 6], [6]]
Upvotes: 0
Reputation: 168081
[1, 2, 3, 3, 4, 4, 5, 6, 6, 6, 7]
.each.with_object([]){|e, a| (a.find{|b| !b.include?(e)} || a.push([]).last).push(e)}
# => [[1, 2, 3, 4, 5, 6, 7], [3, 4, 6], [6]]
Upvotes: 0
Reputation: 15515
A simple solution, but I'm sure it will not have the best performance:
def array_groups(arr)
result = []
arr.uniq.each do |elem|
arr.count(elem).times do |n|
result[n] ||= []
result[n] << elem
end
end
result
end
array_groups [1, 2, 3, 3, 4, 4, 5, 6, 6, 6, 7]
# [[1, 2, 3, 4, 5, 6, 7], [3, 4, 6], [6]]
Upvotes: 0
Reputation: 19879
Not sure about performance, but this works:
Code:
$ cat foo.rb
require 'pp'
array = [1, 2, 3, 3, 4, 4, 5, 6, 6, 6, 7]
result = []
values = array.group_by{|e| e}.values
while !values.empty?
result << values.map{|e| e.slice!(0,1)}.flatten
values = values.reject!{|e| e.empty?}
end
pp result
Output:
$ ruby foo.rb
[[1, 2, 3, 4, 5, 6, 7], [3, 4, 6], [6]]
Upvotes: 1