У меня есть такой массив:
[1, 2, 3, 3, 4, 4, 5, 6, 6, 6, 7]
Я хочу знать, есть ли способ для этого:
[[1, 2, 3, 4, 5, 6, 7], [3, 4, 6], [6]]
Я знаю, что есть Array.uniq
, но это удаляет повторяющиеся элементы, и я хотел бы сохранить их.
У меня есть такой массив:
[1, 2, 3, 3, 4, 4, 5, 6, 6, 6, 7]
Я хочу знать, есть ли способ для этого:
[[1, 2, 3, 4, 5, 6, 7], [3, 4, 6], [6]]
Я знаю, что есть Array.uniq
, но это удаляет повторяющиеся элементы, и я хотел бы сохранить их.
Не уверен в производительности, но это работает:
код:
$ 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
Выход:
$ ruby foo.rb
[[1, 2, 3, 4, 5, 6, 7], [3, 4, 6], [6]]
Вот несколько способов сделать это.
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]]
Помощник Array#difference
определяется в моем ответе здесь.
# 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]]
Этапы для:
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({})>
Чтобы просмотреть элементы enum
:
enum.to_a
#=> [[[1, 1], {}], [[2, 1], {}],...[[7, 1], {}]]
Теперь перейдите к перечислителю и просмотрите хэш после каждого шага:
(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]}
Наконец, извлеките и унифицируйте значения хэша:
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]]
В рубине вы можете добавить метод к классу Array
. Вот так:
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
#=> []
Или вы могли бы сделать это, чтобы сохранить элементы на 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]]
Простое решение, но я уверен, что он не будет иметь лучшую производительность:
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]]
[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]]