我有一个数组
a = ['A', 'B', 'B', 'C', 'D', 'D']
我必须通过所有元素,根据是否是最后一次出现来做某事,并在处理完后删除该元素。
如果重要,元素已经分类。
我正在寻找有效率的东西。有什么建议吗?
她到现在为止。这是预期的,但不确定它是否非常有效。
a = ['A', 'B', 'B', 'C', 'D', 'D']
while !a.empty?
b = a.shift
unless a.count(b) > 0
p "unique #{b}"
else
p "duplicate #{b}"
end
end
并生成
"unique A"
"duplicate B"
"unique B"
"unique C"
"duplicate D"
"unique D"
由于
答案 0 :(得分:4)
简单方法:
array = ["A", "B", "B", "C", "D", "D"]
array.group_by{|e| e}.each do |key,value|
*duplicate, uniq = value
duplicate.map do |e|
puts "Duplicate #{e}"
end
puts "Unique #{uniq}"
end
根据 Stefan's comment 和建议,更短的方法是:
array.chunk_while(&:==).each do |*duplicate, uniq|
duplicate.map do |e|
puts "Duplicate #{e}"
end
puts "Unique #{uniq}"
end
# Above both will give the same Output:
---------------------------------------
Unique A
Duplicate B
Unique B
Unique C
Duplicate D
Unique D
答案 1 :(得分:1)
根据您的代码和预期输出,我认为这是您正在寻找的有效方式:
ALTER procedure [dbo].[usp_ExportData]
(
@StartDate Date,
@EndDate Date
)
AS
BEGIN
declare @sql varchar(max)
set @sql = ''
set @sql += ' Select REPLACE(U.EmployeeID, '','','') as
EmployeeID,REPLACE(U.ClientID, '','','') as ClientID,REPLACE(U.ID, '','','') as ID,
REPLACE(U.FirstName, '','','')as FirstName,REPLACE(U.MiddleName, '','','')as MiddleName,
REPLACE(U.LastName, '','','')as LastName,REPLACE(U.Email, ',','')as
Email,REPLACE(U.SSN, '','','')as SSN,
REPLACE(U.DateOfBirth, '','','')as DateOfBirth,REPLACE(U.Gender, '','','')as
Gender,REPLACE(U.CreatedDate, '','','')as CreatedDate,
REPLACE(U.ModifiedDate, '','','')as ModifiedDate, REPLACE(UPI.StreetAddress1,
'','','')as StreetAddress1,
REPLACE(UPI.StreetAddress2, '','','')as StreetAddress2,REPLACE(UPI.City, '','','')as
City,
REPLACE(UPI.State, '','','')as State,
REPLACE(UPI.ZipCode, '','','')as ZipCode,
REPLACE(UPI.CellPhoneNumber, '','','')as CellPhoneNumber, '' as Department, '' as
JobTitle, '' as StreetAddress3 from Users U INNER JOIN PersonalContacts UPI ON
U.ID= UPI.UserID'
if(@StartDate <> '' or @EndDate <> '')set @sql += ' where U.ModifiedDate >='''+@StartDate+''' and U.ModifiedDate<= '''+@EndDate+''''
exec(@sql)
END
但我想重申我的输出中的措辞与你的措辞的重要性。这与输入中的值是否唯一无关。这似乎是关于值是否是输入中的 last 出现。
答案 2 :(得分:1)
与@GaganGami的答案非常相似,但使用chunk_while
。
a.chunk_while { |a,b| a == b }
.each do |*list,last|
list.each { |e| puts "duplicate #{e}" }
puts "unique #{last}"
end
当元素发生变化时, chunk_while
将数组拆分为子数组。
['A', 'B', 'B', 'C', 'D', 'D'].chunk_while { |a,b| a == b }.to_a
# => [["A"], ["B", "B"], ["C"], ["D", "D"]]
答案 3 :(得分:1)
OP表示a
的元素已经排序,但我建议的方法不需要这样做。它还维护了数组顺序,这对于为要删除的每个元素执行的“执行某些操作”代码非常重要。它在数组已经排序的情况下没有性能损失。
对于数组
['A', 'B', 'D', 'C', 'B', 'D']
我假设要为'A'
执行某些代码,'C'
第二个'B'
和第二个'D'
,按顺序执行之后是一个新数组
['B', 'D']
返回。
<强>代码强>
def do_something(e) end
def process_last_dup(a)
a.dup.
tap do |b|
b.each_with_index.
reverse_each.
uniq(&:first).
reverse_each { |_,i| do_something(a[i]) }.
each { |_,i| b.delete_at(i) }
end
end
示例强>
a = ['A', 'B', 'B', 'C', 'D', 'D']
process_last_dup(a)
#=> ["B", "D"]
<强>解释强>
步骤如下。
b = a.dup
#=> ["A", "B", "B", "C", "D", "D"]
c = b.each_with_index
#=> #<Enumerator: ["A", "B", "B", "C", "D", "D"]:each_with_index>
d = c.reverse_each
#=> #<Enumerator: #<Enumerator: ["A",..., "D"]:each_with_index>:reverse_each>
请注意,d
可以被视为“复合”枚举器。我们可以将它转换为数组,以查看它将生成的元素并传递给uniq
。
d.to_a
#=> [["D", 5], ["D", 4], ["C", 3], ["B", 2], ["B", 1], ["A", 0]]
继续,
e = d.uniq(&:first)
#=> [["D", 5], ["C", 3], ["B", 2], ["A", 0]]
e.reverse_each { |_,i| do_something(a[i]) }
reverse_each
用于do_something
首先执行'A'
,然后执行第二'B'
,依此类推。
e.each { |_,i| b.delete_at(i) }
b #=> ["B", "D"]
如果要对a
进行修改,请将a.dup.
替换为a.
。
读者可能已经注意到我在开头使用的代码Object#tap使得tap
的块变量b
(最初等于a.dup
)将被返回在tap
块内修改后,而不是在开头明确设置b = a.sup
,在结尾处b
明确设置,就像我在逐步说明中所做的那样。当然,这两种方法都会产生相同的结果。
Enumerable#uniq的文档未指定是否保留第一个元素,但它确实引用了Array.uniq,它确实保留了第一个元素。如果对此有任何不安,可以随时将reverse_each
替换为reverse
,以便Array.uniq
使用。