[英]Ruby counting duplicates in array and print into new file
我需要计算数组中重复项的数量,找出它们出现的次数,然后将其放入文档中。.这就是我所做的,现在我不知道如何进行操作了。数据来自另一个txt文件。 如果这有点混乱,我深表歉意,但是我现在很困惑。
class Ticket
attr_accessor :ticknum
attr_accessor :serialnum
def initialize(ticknum,serialnum)
@ticknum = ticknum
@serialnum = serialnum
end
end
class Ticketbook
def initialize
@ticketbook = Array.new
end
def newticket(ticket)
@ticketbook << ticket
@ticketbook.sort! {|x,y| x.ticknum*1000 + x.serialnum <=> y.ticknum*1000 + y.serialnum}
end
def soldnumber(tickenum2,serialnum2)
@ticknum2 = ticknum2
@serialnumb2 = serialnum2
@antal = 0
for i in 0..@ticketbook.length-1
if @ticknum2 == @ticketbook[i].ticknum && @serialnum2 == @ticketbook[i].serialnum
@antal +=1
end
end
return @antal
end
end
ticketfile = File.open("tickets.txt", "r")
book = Ticketbook.new
ticketfile.each {|line|
a = line.split(",")
newdoc = Ticket.new(a[0].to_i,a[1].to_i)
book.newticket(newdoc)
}
registernums = File.new("registernums.txt", "w")
for i in (0..@ticketbook.length-1)
registernums.print book[i].@ticketnum.to_i + ", "
registernums.print book[i].@serialnumber.to_i + ", "
registernums.puts book[i].soldnumber(i)
end
print registernums
给我这个错误:rb 56意外的tIVAR,期望“(” registernums.print book [i]。@ ticketnum.to_i rb 57意外的tIVAR,期望“(” registernums.print book [i]。@ serialnum.to_i
您的for
循环没有主体,因此您的最后几行引用i
在未定义循环的外部。
问题在于这些行。
registernums.print book[i].@ticketnum.to_i + ", "
registernums.print book[i].@serialnumber.to_i + ", "
要访问任何对象的实例变量,您无需放置@
。 所以正确的代码应该是
registernums.print book[i].ticketnum.to_i + ", "
registernums.print book[i].serialnumber.to_i + ", "
就像@Jonah指出的那样,应该在最后一个for循环的end
结束。
这里有一些问题:
for i in (0..@ticketbook.length-1)
registernums.print book[i].@ticketnum.to_i + ", "
registernums.print book[i].@serialnumber.to_i + ", "
registernums.puts book[i].soldnumber(i)
print registernums
该代码在TicketBook
类之外,因此实际上没有任何实例变量(以@
开头的实例变量)。
如果要从TicketBook外部访问票证阵列,请创建一个
attr_reader :ticketbook
在TicketBook
类中。
您可能想要用以下内容替换代码:
book.ticketbook.each_with_index do |tb, i|
registernums.print tb.ticketnum.to_i + ", "
registernums.print tb.ticketnum.to_i + ", "
registernums.puts tb.soldnumber(i)
end
好家伙!
在开始一些重要说明之前:-您正在过度使用实例变量-票证类可以,但是Ticketbook(应为TicketBook)应仅具有一个instance_variable(在initialize方法中设置的一个),其余应位于方法作用域的局部。
Ruby的命名约定是用_分隔单词(new_doc,ticket_file等)
您几乎应该永远不要使用for
循环-使用它的唯一原因是编写自己的迭代器,但是您在此处作用于数组-请使用each
方法
现在,关于错误:
ticketfile = File.open("tickets.txt", "r")
book = Ticketbook.new
ticketfile.each {|line|
a = line.split(",")
newdoc = Ticket.new(a[0].to_i,a[1].to_i)
book.newticket(newdoc)
}
registernums = File.new("registernums.txt", "w")
for i in (0..@ticketbook.length-1) # @ticketbook is an instance variable of Ticketbook, you'll get undefined length for nil:NilClass
registernums.print book[i].@ticketnum.to_i + ", " # book is an instance of Ticketbook, [] is not defined on that class!
registernums.print book[i].@serialnumber.to_i + ", "
registernums.puts book[i].soldnumber(i)
print registernums
您的票务类
class Ticketbook
def initialize
@ticketbook = Array.new #personaly would prefer []
end
def newticket(ticket)
@ticketbook << ticket
@ticketbook.sort! {|x,y| x.ticknum*1000 + x.serialnum <=> y.ticknum*1000 + y.serialnum}
end
def soldnumber(tickenum2,serialnum2)
@ticknum2 = ticknum2 # unnecessary
@serialnumb2 = serialnum2 # unnecessary
@antal = 0
for i in 0..@ticketbook.length-1 # Should be @ticketbook.each do |ticket|
if @ticknum2 == @ticketbook[i].ticknum && @serialnum2 == @ticketbook[i].serialnum
@antal +=1
end
end
@antal
# much better would be:
# def soldnum(ticknum2, serialnum2)
# @ticketbook.select {|ticket| ticket.ticknum == ticknum2 && ticket.serialnum == serialnum }.count
# end
end
结束
我还将向您介绍group_by
方法-在数组上运行会将其转换为一个非常漂亮的哈希,其中键是已执行块的结果:
[1,2,3,4,5,6].group_by {|e| e.odd?} #=> {true => [1,3,5], false => [2,4,6]}
您可以使用它来一次性获得重复计数:
# inside ticket book
def count_repetitions
Hash[@ticketbook.group_by {|e| [e.ticknum, e.serialnum]}.map {|key, value| [key, value.count]}
end
这应该返回哈希,其中键是包含ticknum和serialnum的两个元素的数组,值是出现的次数
tIVAR
引用了一个实例变量,因此错误消息unexpected tIVAR
表示ruby在某处不期望使用实例变量,并且它指向此行(及其后的一行)
registernums.print book[i].@ticketnum.to_i + ", "
访问对象中的属性不使用@
字符(也不是变量名的一部分)。 访问您的ticketnum
属性的正确方法是
registernums.print book[i].ticketnum.to_i + ", "
回答完您的问题后,我想提出一种更“类似于Ruby”的方式来处理您的问题。 首先,几点:
Ticket
类的实例,就像已经完成的那样,由两个元素组成的数组,但要理解的是,第一个和第二个元素分别对应于票证和序列号,或者使用一个键作为哈希值表示票号,另一个表示序列号。 我赞成哈希。 我认为不需要单独的类,我认为使用数组更可能导致编码错误(例如,如果您为票证或序列号使用了错误的数组元素)。 Enumerable
“ mixin”模块中提供的所有方法,无需循环索引。 避免这种循环将使您的代码更紧凑,更易于阅读并且更不可能包含错误。 首先,向票务ticketbook
添加一些票证:
ticketbook = []
ticketbook << {tnbr: 22, snbr: 55}
ticketbook << {tnbr: 27, snbr: 65}
ticketbook << {tnbr: 22, snbr: 56}
ticketbook << {tnbr: 27, snbr: 66}
# => [{:tnbr=>22, :snbr=>55}, {:tnbr=>27, :snbr=>65}, \
{:tnbr=>22, :snbr=>55}, {:tnbr=>27, :snbr=>65}]
现在查找重复项(具有相同票证编号但序列号不同的票证)。 一旦您对Ruby有了更多的经验,每当您想要按某个特征对数组的元素进行分组时,便会想到Enumerable#group_by
方法(或者可能是Enumerable#chunk
):
g0 = ticketbook.group_by {|t| t[:tnbr]}
# => {22=>[{:tnbr=>22, :snbr=>55}, {:tnbr=>22, :snbr=>56}], \
# 27=>[{:tnbr=>27, :snbr=>65}, {:tnbr=>27, :snbr=>66}]}
如您所见,当我们对票证编号进行group_by
时,我们将获得一个包含元素(k,v)
的哈希,其中键k
是票证编号,值v
是具有该票证编号的票证(哈希)数组。
这可能就是您所需要的。 如果要对具有相同序列号的票证数量进行计数,可以使用Enumerable#map
将g0
哈希(具有相同票证号的票证数组)中的每个值转换为此类票证的数量:
g1 = g0.map {|k,v| {k => v.size}} # => [{22=>2}, {27=>2}]
您可能会在这里停下来,但是如果这是一个哈希( {22=>2, 27=>2}
),而不是一个单对哈希数组,将会更加方便。 您可以通过多种方式将此数组转换为哈希。 一种是使用map
将哈希值转换为数组:
g2 = g1.map(&:to_a) # => [[[22, 2]], [[27, 2]]]
(其中map(&:to_a)
是map {|h| h.to_a}
简写),然后使用Array#flatten
将其转换为:
g3 = g2.flatten # => [22, 2, 27, 2]
创建哈希的一种方法(通常)是这样的:
Hash[1,2,3,4] # => {1=>2, 3=>4}
为此,我们需要在数组g3
上添加“ splat”运算符:
Hash[*g3] # => {22=>2, 27=>2}
这为我们提供了所需的按票号计数的哈希值。 我说过,这是将单对散列数组转换为哈希的一种方法。 这是一种更直接的方法:
g1.pop.merge(*g1) # => {27=>2, 22=>2}
在这里, g1.pop
返回{27=>2}
并将g1
转换为[{22=>2}]
。 因此,以上表达式等效于:
{27=>2}.merge(*[{22=>2}]) # => {27=>2, 22=>2}
它将散列数组中的哈希(此处仅是一个) merge
到merge
之前的哈希中。
通常不用“链接”这三个操作,而不必引入局部变量g0
和g1
:
ticketbook.group_by {|t| t[:tnbr]}.map {|k,v| {k => v.size}}.pop.merge(*g1)
# => {27=>2, 22=>2}
最后,虽然您的sort
版本很好,但是您也可以这样:
ticketbook.sort! {|x,y| (x <=> y) == 0 ? x[:snbr] <=> y[:snbr] : \
x[:tnbr] <=> y[:tnbr]}
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.