获取具有唯一元素的数组

get an array of arrays with unique elements

我有一个这样的数组:

[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 在我的回答 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]]

步骤,适用于:

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]]

在 ruby 上,您可以向 class 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]]