2015-11-10 36 views
1

我有一个name.txt文件和last.txt文件。我想生成所有可能的名字和姓氏的组合。例如:读取两个文件和输出结果在Ruby中

$cat name.txt 
Jack 
Jamie 
James 
Jarred 
Josh 
John 
Jane 


$cat last.txt 
doe 
smith 

我试着这样做:

File.open("name.txt", "r") do |n| 


File.open("last.txt", "r") do |l| 
    n.each_line do |first| 
     l.each_line do |last| 
      full_name = first.chomp + " " + last.chomp 
      puts full_name 
     end 
    end 
    end 
end 

输出只显示它仅处理名称文件的第一行:

Jack doe 
Jack smith 

我怎样才能有它经过整个第一文件提供所有的名字全名在name.txt

回答

2

要获得每个线文本文件,你必须使用each这样的:

​​

因此,使用each您的代码工作:

File.open("name.txt", "r").each do |n| 
File.open("last.txt", "r").each do |l| 
    n.each_line do |first| 
     l.each_line do |last| 
      full_name = first.chomp + " " + last.chomp 
      puts full_name 
     end 
    end 
    end 
end 

虽然这个工程,解决你的问题,但它不是一种有效的阅读文件的方式。

要使其有效,你应该使用readlines来一次读取整个文件的内容,并保存在数组中。这方面的更多详情,请参见this answer

names = File.readlines('name.txt') 
last_names = File.readlines('last.txt') 

names.each do |n| 
last_names.each do |l| 
    n.each_line do |first| 
     l.each_line do |last| 
      full_name = first.chomp + " " + last.chomp 
      puts full_name 
     end 
    end 
    end 
end 
+1

啊!真棒,男人!谢谢! – user3610137

+0

这样就打开了'last.txt'并且读取的是'''''''''''''''''这个效率相当低的数字。相反,将文件内容读入一个变量并在其上循环将会*效率更高,尤其是,当文件将变得更大时。 –

+0

我同意。我没有去找高效的代码。我只是更新了他的当前代码来完成这项工作,在这种情况下,我只是添加了'.each'和他自己的代码,这个小改动:) –

3

考虑这个:

first = %w[jane john] 
last = %w[doe smith] 

first.product(last) 
# => [["jane", "doe"], ["jane", "smith"], ["john", "doe"], ["john", "smith"]] 

你可以做这样的事情:

first = File.readlines('name.txt').map(&:rstrip) 
last = File.readlines('last.txt').map(&:rstrip) 
first.product(last) 

product

所以,如果这样写你的代码可以更有效Array的一种方法。另外,也要看看permutationcombination

我们可以用chomp代替rstrip删除尾随新线,这将是readlines被退回,但chomp只修剪新线,而rstrip将删除尾随的空白,清理名字有点如果有任何尾随的空白。 (在我的经验它更可能我们将看到的文字比以前后的空白,因为它更容易看到,当它处于领先地位。)


基准:

require 'fruity' 

FIRST_NAME = [*'a'..'z'] 
LAST_NAME = [*'a'..'z'] 

FIRST_NAME.size # => 26 
LAST_NAME.size # => 26 

def use_product 
    FIRST_NAME.product(LAST_NAME) 
end 

def use_loops 
    output = [] 
    FIRST_NAME.each do |fn| 
    LAST_NAME.each do |ln| 
     output << [fn, ln] 
    end 
    end 
    output 
end 

result = use_product 
result.size # => 676 
result.first # => ["a", "a"] 
result.last # => ["z", "z"] 

result = use_loops 
result.size # => 676 
result.first # => ["a", "a"] 
result.last # => ["z", "z"] 

运行它导致:

compare :use_product, :use_loops 
# >> Running each test 64 times. Test will take about 1 second. 
# >> use_product is faster than use_loops by 50.0% ± 10.0% 

如果在大小源阵列增加:

require 'fruity' 

FIRST_NAME = [*'a1'..'z9'] 
LAST_NAME = [*'a1'..'z9'] 

FIRST_NAME.size # => 259 
LAST_NAME.size # => 259 

def use_product 
    FIRST_NAME.product(LAST_NAME) 
end 

def use_loops 
    output = [] 
    FIRST_NAME.each do |fn| 
    LAST_NAME.each do |ln| 
     output << [fn, ln] 
    end 
    end 
    output 
end 

result = use_product 
result.size # => 67081 
result.first # => ["a1", "a1"] 
result.last # => ["z9", "z9"] 

result = use_loops 
result.size # => 67081 
result.first # => ["a1", "a1"] 
result.last # => ["z9", "z9"] 

运行返回:

compare :use_product, :use_loops 
# >> Running each test once. Test will take about 1 second. 
# >> use_product is faster than use_loops by 60.00000000000001% ± 10.0% 

虽然我们可以编写算法没有考虑的内置方法的优势,该方法是用C写的所以利用它们来获取他们的加入了倍速。

有一段时间我会在内置的product上使用单独数组的迭代:如果我有两个巨大的列表,并且由于RAM约束导致可伸缩性问题而将它们拉到内存中,那么只有这样才能处理它将是嵌套循环。 Ruby's foreach is extremely fast,所以在它周围写代码将是一个很好的替代:

File.foreach('name.txt') do |first| 
    File.foreach('last.txt') do |last| 
    full_name = first.chomp + " " + last.chomp 
    puts full_name 
    end 
end 
相关问题