我想使用Array
方法扩展uniq_elements
类,该方法返回多重性为1的元素。我也想像uniq
一样使用闭包到我的新方法。例如:
t=[1,2,2,3,4,4,5,6,7,7,8,9,9,9]
t.uniq_elements # => [1,3,5,6,8]
关闭示例:
t=[1.0, 1.1, 2.0, 3.0, 3.4, 4.0, 4.2, 5.1, 5.7, 6.1, 6.2]
t.uniq_elements{|z| z.round} # => [2.0, 5.1]
t-t.uniq
和t.to_set-t.uniq.to_set
都不起作用。我不关心速度,我在程序中只调用一次,所以它可能很慢。
答案 0 :(得分:11)
帮助方法
此方法使用帮助程序:
class Array
def difference(other)
h = other.each_with_object(Hash.new(0)) { |e,h| h[e] += 1 }
reject { |e| h[e] > 0 && h[e] -= 1 }
end
end
此方法类似于Array#-。以下示例说明了不同之处:
a = [3,1,2,3,4,3,2,2,4]
b = [2,3,4,4,3,4]
a - b #=> [1]
c = a.difference b #=> [1, 3, 2, 2]
如您所见,a
包含三个3&{39},b
包含两个,因此首先 {3}中的两个3&#39}在构建a
时删除(c
未变异)。当a
包含与b
一样多的元素实例时,a
不包含该元素的实例。要删除从c
结尾处开始的元素:
a
a.reverse.difference(b).reverse #=> [3, 1, 2, 2]
可以用明显的方式定义。
我发现此方法有很多用途:here,here,here,here,here,here,{{ 3}},here,here,here,here,here,here,here,{{3} },here,here,here,here,here,here,here和here。
我有here将此方法添加到Ruby核心。
与Array#difference!
一起使用时,此方法可以轻松从数组Array#-
中提取唯一元素:
a
这是因为
a = [1,3,2,4,3,4]
u = a.uniq #=> [1, 2, 3, 4]
u - a.difference(u) #=> [1, 2]
包含a.difference(u) #=> [3,4]
的所有非唯一元素(每个元素可能不止一次)。
手头的问题
代码的
a
实施例
class Array
def uniq_elements(&prc)
prc ||= ->(e) { e }
a = map { |e| prc[e] }
u = a.uniq
uniques = u - a.difference(u)
select { |e| uniques.include?(prc[e]) ? (uniques.delete(e); true) : false }
end
end
答案 1 :(得分:3)
这是另一种方式。
<强>代码强>
require 'set'
class Array
def uniq_elements(&prc)
prc ||= ->(e) { e }
uniques, dups = {}, Set.new
each do |e|
k = prc[e]
((uniques.key?(k)) ? (dups << k; uniques.delete(k)) :
uniques[k] = e) unless dups.include?(k)
end
uniques.values
end
end
<强>实施例强>
t = [1,2,2,3,4,4,5,6,7,7,8,9,9,9]
t.uniq_elements #=> [1,3,5,6,8]
t = [1.0, 1.1, 2.0, 3.0, 3.4, 4.0, 4.2, 5.1, 5.7, 6.1, 6.2]
t.uniq_elements { |z| z.round } # => [2.0, 5.1]
<强>解释强>
uniq_elements
,则会将其作为proc prc
接收。uniq_elements
,prc
为nil
,则方法的第一个语句将prc
设置为等于默认的proc(lambda)。< / LI>
uniques
,包含唯一值的表示。值是数组self
的唯一值,键是proc prc
传递数组值并调用时返回的值:k = prc[e]
。dups
包含已发现不唯一的数组元素。它是一个加速查找的集合(而不是数组)。或者,如果可以是具有非唯一值作为键和任意值的散列。 e
的每个元素self
执行以下步骤:
k = prc[e]
。dups
包含k
,e
是一个副本,那么就不需要做任何事了;其他uniques
有一个密钥k
,e
是一个副本,那么k
会被添加到集合dups
和带有密钥{{}的元素1}}已从k
中移除;其他uniques
被添加到k=>e
作为唯一元素的候选者。uniques
的值。答案 2 :(得分:1)
class Array
def uniq_elements
counts = Hash.new(0)
arr = map do |orig_val|
converted_val = block_given? ? (yield orig_val) : orig_val
counts[converted_val] += 1
[converted_val, orig_val]
end
uniques = []
arr.each do |(converted_val, orig_val)|
uniques << orig_val if counts[converted_val] == 1
end
uniques
end
end
t=[1,2,2,3,4,4,5,6,7,7,8,9,9,9]
p t.uniq_elements
t=[1.0, 1.1, 2.0, 3.0, 3.4, 4.0, 4.2, 5.1, 5.7, 6.1, 6.2]
p t.uniq_elements { |elmt| elmt.round }
--output:--
[1, 3, 5, 6, 8]
[2.0, 5.1]
Array #uniq没有找到非重复的元素,而是Array #uniq删除了重复的元素。
答案 3 :(得分:0)
class Array
def uniq_elements
zip( block_given? ? map { |e| yield e } : self )
.each_with_object Hash.new do |(e, v), h| h[v] = h[v].nil? ? [e] : false end
.values.reject( &:! ).map &:first
end
end
[1,2,2,3,4,4,5,6,7,7,8,9,9,9].uniq_elements #=> [1, 3, 5, 6, 8]
[1.0, 1.1, 2.0, 3.0, 3.4, 4.0, 4.2, 5.1, 5.7, 6.1, 6.2].uniq_elements &:round #=> [2.0, 5.1]
答案 4 :(得分:0)
...
require 'set'
class Array
def uniq_elements
uniques = {}
dups = Set.new
each do |orig_val|
converted_val = block_given? ? (yield orig_val) : orig_val
next if dups.include? converted_val
if uniques.include?(converted_val)
uniques.delete(converted_val)
dups << converted_val
else
uniques[converted_val] = orig_val
end
end
uniques.values
end
end
t=[1,2,2,3,4,4,5,6,7,7,8,9,9,9]
p t.uniq_elements
t=[1.0, 1.1, 2.0, 3.0, 3.4, 4.0, 4.2, 5.1, 5.7, 6.1, 6.2]
p t.uniq_elements {|elmt|
elmt.round
}
--output:--
[1, 3, 5, 6, 8]
[2.0, 5.1]
答案 5 :(得分:0)
class Array
def uniq_elements
tally.select { |_obj, nb| nb == 1 }.keys
end
end
t=[1,2,2,3,4,4,5,6,7,7,8,9,9,9]
t.uniq_elements # => [1,3,5,6,8]
如果您使用的是Ruby <2.7,则可以使用backports gem来获得tally
require 'backports/2.7.0/enumerable/tally'