我需要计算数组中重复项的数量,找出它们出现的次数,然后将它放入文档中......这就是我所做的,现在我对如何继续进行无能为力...... ..数据来自另一个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
答案 0 :(得分:1)
您的for
循环没有正文,因此您的最后几行在未定义的循环之外引用i
。
答案 1 :(得分:1)
问题出在这些方面。
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指出,应该有一个end
来结束最后一个for循环。
答案 2 :(得分:1)
这里有一些问题:
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
答案 3 :(得分:1)
哦,男孩!
在我开始几个要点之前: - 你过度使用实例变量 - Ticket类没问题,但是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
您的Ticketbook课程
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的双元素数组,值是出现次数
答案 4 :(得分:0)
tIVAR
指的是一个实例变量,因此错误消息unexpected tIVAR
意味着ruby不会在某处预期某个实例变量,而是指向此行(以及后面的那个)
registernums.print book[i].@ticketnum.to_i + ", "
访问对象中的属性不使用@
字符(并且它也不是变量名称的一部分)。访问ticketnum
属性的正确方法是
registernums.print book[i].ticketnum.to_i + ", "
答案 5 :(得分:0)
当你的问题得到解答时,我想建议一种更“类似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}
将splatted数组中的哈希值(此处只有一个)合并到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]}