【问题标题】:In Ruby, what is the best way to hash two columns that share some values?在 Ruby 中,散列共享某些值的两列的最佳方法是什么?
【发布时间】:2015-10-11 19:10:20
【问题描述】:

第一列有一些用户,第二列有他们的朋友。有些用户出现在两列中,有些用户只出现在一个列中。

我想对整个数据集进行哈希处理以将所有条目转换为数字以便于处理。我的代码是这样的:

require 'csv'

udids = {}
unique_count = 1

output_csv = CSV.open("Processed.csv", "w")

CSV.foreach("Original.csv").with_index do |row, i|

  val = row[0]
  if udids[val.to_sym]
    row[0] = udids[val.to_sym]
  else
    udids[val.to_sym] = unique_count
    row[0] = unique_count
    unique_count += 1
  end

  val = row[1]
  if udids[val.to_sym]
    row[1] = udids[val.to_sym]
  else
    udids[val.to_sym] = unique_count
    row[1] = unique_count
    unique_count += 1
  end

  output_csv << row
end

output_csv.close

但这产生了我认为可能不是正确的转换。这是一个示例输出:

1   2
1   3
1   4
1   5
1   51
1   52
1   53
54  55
54  56
54  57
54  58
54  59
54  90
54  91
54  92
93  94
93  95
93  96
...

在这里,2 列不共享任何单个值,而这种情况极不可能发生。另外,即使这是正确的,我也希望它能够将其作为相应的示例输出:

1   2
1   3
1   4
1   5
1   51
1   52
1   53
2   55
2   56
2   57
2   58
2   59
2   90
2   91
2   92
3   94
3   95
3   96
...

那么,谁能帮帮我?谢谢。

【问题讨论】:

  • 您能否将您提供给此脚本的输入发布,以便那些试图帮助您的人重现您的结果?我刚刚在一个小数据集上测试了你的程序,发现它没有问题。
  • @DavidGrayson 它是一个 3 MB 的文件。我不确定如何在这里分享。有什么建议吗?
  • 您应该将其缩减为能够说明问题的最小文件,并将名称更改为假名。例如,文件的前 200 行可能足以显示问题,之后您可以删除所有内容。如果问题仍然存在,请删除前 20 行之后的所有内容。继续。

标签: ruby csv


【解决方案1】:

很难在没有看到您的输入的情况下调试您的程序。我猜您的代码的一个问题是 CSV 文件中有空格。由于您没有去除空格,因此名称“David”将与名称“David”不同,并获得不同的 ID。

这里有一些代码对我来说很好用,而且更短:

require 'csv'

udids = {}
unique_count = Enumerator.new do |y|
  c = 0
  loop { y << (c += 1) }
end

output_csv = CSV.open('output.csv', 'w')

CSV.foreach('students.csv') do |row|
  row[0] = (udids[row[0].strip] ||= unique_count.next)
  row[1] = (udids[row[1].strip] ||= unique_count.next)
  output_csv << row
end

output_csv.close

【讨论】:

  • 枚举器的有趣使用。起初我认为loop 有一些有趣的事情可以让它发挥作用,但我刚刚读到&lt;&lt; 别名为yield。我仍在尝试理解“yielder”对象。
【解决方案2】:

唯一 ID 值

要为给定的集合生成唯一的数字 ID,我首先定义如下哈希:

uniqueIdHash = Hash.new { |hash, key| hash[key] = hash.size }

根据 Ruby 文档,Hash.new 可以采用具有以下含义的块:

如果此哈希随后被不对应的键访问 对于哈希条目,返回的值取决于新使用的样式 创建哈希。
. . .
如果指定了一个块,它将使用哈希对象调用,并且 键,并且应该返回默认值。这是块的 如果需要,负责将值存储在哈希中。

使用上面建议的块,每次在哈希中查找未知值时,都会添加一个新的唯一编号(添加之前哈希中的项目数)。

如果该值以前不存在,则只需尝试通过散列转换值就会生成一个唯一 ID,如果现在确实存在,则返回以前的 ID。

处理 CSV

在已处理的 CSV 文件的示例输出中,您为第一列保留了优先级。为此,可以将数据传递两次,第一次查找(并因此添加)第一列到唯一 ID 哈希。然后第二遍将分配来自第二列后续 ID 号的未知值。代码如下:

require 'csv'

def convertCsvNamesToNums(inputFileName, outputFileName)
    # Create unique ID number hash
    # When unknown key is lookedup, it is added with new unique ID number
    # Produces a 0 based index
    nameHash = Hash.new { |hash, key| hash[key] = hash.size }
    # Pass over the data once to give priority to user column for ID numbers
    CSV.open(inputFileName, "r") do |inputFile|
        inputFile.each do |name,|
            nameHash[name]  # Add name to unique ID number hash (if it doesn't already exist)
        end
    end
    # Convert input CSV with names to output CSV with ID numbers
    CSV.open(inputFileName, "r") do |inputFile|
        CSV.open(outputFileName, 'w') do |outputFile|
            inputFile.each do |row|
                # Parse names from input, map to ID numbers, and write to output
                outputFile << row.map{|name| nameHash[name]}
            end
        end
    end
end

convertCsvNamesToNums("Original.csv", "Processed.csv")

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2021-05-21
    • 1970-01-01
    • 2014-01-15
    • 2010-09-09
    • 1970-01-01
    • 2016-12-19
    • 2020-08-07
    • 2016-06-29
    相关资源
    最近更新 更多