仅包含非重复值的数组

3
这不是问题,更像一个疑问,是否有其他方法可以做到这一点: 我有一个数组:
arr = [1,2,3,4,4,5,1,4,3]

我希望得到这个输出:[2,5]

我的代码看起来像这样:

arr.select { |e| arr.count(e) == 1}

这个有没有其他替代方案?

3
请分为两个不同的帖子来提出两个问题。你的第二个问题已经被回答了,可以在此链接中查看。 - toro2k
谢谢,我已经删除了另一个问题。 - Eugen
@bjhaid OP想要非唯一元素... - Arup Rakshit
3个回答

10

试一试

arr.group_by { |e| e }.select { |k, v| v.size.eql? 1 }.keys
 => [2, 5] 

3
你可以使用keys代替collect(&:first) - Mark Thomas
1
就可读性而言,这绝对不比他已经有的更好。 - Mischa
3
OP 的解决方案的主要问题不是可读性,而是每个元素的完整数组扫描,其性能为 O(n^2)。 - Mark Thomas
2
我已经在基准测试中测试了这两个解决方案的性能,我的解决方案快了近7倍。相对于size方法所需的时间,count方法需要更多的执行时间。 - Alok Anand
1
a.group_by { |e| e }(这里 => {1=>[1, 1], 2=>[2], 3=>[3, 3], 4=>[4, 4, 4], 5=>[5]})如果元素经常出现,将会占用相当多的内存。 - mvw
显示剩余2条评论

4

您的代码将针对每个元素扫描数组一次,这对于小型数组是可以接受的,但并不是必要的。通过查看这篇博客文章,很容易想出更好的方法。

arr = [1,2,3,4,4,5,1,4,3]
counts=Hash.new(0)

arr.each do |el|
  counts[el]+=1
end

counts.select do |key, count|
  count == 1
end.keys

这会产生相同的结果,但仅遍历您的数组一次(虽然需要两个额外的哈希表(如果您不需要“counts”,则可以通过使用select! 将其减少到一个哈希表 :-)。

谢谢@bjhaid,我没有想到,当然你会在一行代码中使用select!;-) - Patru
1
arr.each_with_object(Hash.new(0)) { |x,h| h[x] += 1 }.select { |k,v| v == 1 }.keys 是一个简洁的一行代码 :) - bjhaid

4

首先需要全面了解整个数组,才能决定其唯一性。

def one(a)
  o = { }
  a.each do |x|
    v = o[x]
    if v == nil
      o[x] = true
    else
      if v
        o[x] = false
      end
    end
  end
  return o
end

然后使用这个方法来选择唯一的元素。
def unique(a)
  o = one(a)
  b = [ ]
  o.each do |k, v|
    if v
      b.push(k)
    end
  end
  return b
end

测试代码

a = [ 1, 2, 3, 4, 4, 5, 1, 4, 3 ]
b = unique(a)
puts "unique: #{a} -> #{b}"

输出

unique: [1, 2, 3, 4, 4, 5, 1, 4, 3] -> [2, 5]

致Edsger W. Dijkstra先生

现代的、有能力的程序员不应该是谜题迷,不应该沉溺于技巧,他应该谦虚并避免像瘟疫一样的聪明解决方案。

(来自EWD303)


我在意识到没有必要计数超过2之后进行了更新,因此即使我们有高重复率,也可以保持计数较小。你能否更新一下那个基准测试? - mvw

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接