2012-08-02 56 views
2

我遇到这个相当频繁。我有一批数据(存储在CSV,XML,没关系)在某些版本的格式:重组数据从平面文件到散列键的算法

key1|value1 
key1|value2 
key1|value3 
key2|value4 
key2|value5 
etc. 

,需要能够处理它以这种形式:

data[key1] => [value1, value2, value3] 
data[key2] => [value4, value5] 
etc. 

从A转换到B的最佳方法是什么?我通常像这样(伪代码)循环遍历列表,但我不喜欢我必须重复我的数组构建代码。

data = [] 
values = [] 
currentKey = "" 
foreach (line in inputData) { 
    key, value = split(line) 
    if ((currentKey != "") and (currentKey != key)) { 
     data[currentKey] = values 
     values = [] 
    } 
    currentKey = key 
    values.add(value) 
} 
// this is the part I don't like, but it's necessary to capture the last group 
data[currentKey] = values 

我特别没有命名语言,因为我必须至少在Javascript,C#,Perl和PHP中这样做。如果有特定语言的解决方案会很棒,但我真的在寻找最高效的通用算法方法。

+3

你的算法使用的值是按键分组的事实。实际上,你可以避免这种情况,使代码更清晰:if(!(key in dictionary))dictionary.add(key,empty);字典[key] .add(value) – Vlad 2012-08-02 17:03:25

+0

我认为在简化问题时我丢失了一个重要的部分,这就是我经常需要在将数据放入数据之前收集所有的值[currentKey] - 有时它是一个SQL调用或我正在写出一个文件。我认为更大的问题是,我试图通过结合阅读和写作来变得可爱,并且应该循环以解析一次,然后循环解析的数据以创建输出。 – 2012-08-03 05:56:56

回答

1

您可以更改您的代码如下:

data = {} 

currentKey = "" 

foreach (line in inputData) { 

    key, value = split(line) 
    if (currentKey != key) { 
     data[key] = [] // like data.put(key,new ArrayList<String>()) in java 
    } 
    data[key].add(value) // like data.get(key).add(value) in java 
    currentKey = key 
} 
+2

可能最好跳过整个'currentkey'业务,并检查每个行的散列/字典/数组中是否存在密钥,如果不存在,则为其添加一个空数组。这避免了整个“键必须分组在输入”问题。 – geoffspear 2012-08-02 17:37:06

+0

你说得对,我就是这么做的。我以为他只想解决最后一个问题。 – barak1412 2012-08-02 18:50:56

1

这里是一个解决方案。首先,创建一个地图。对于数据文件中的每个条目,找到键和值。检查钥匙是否在地图上。如果不是,则将新的列表添加到包含该键的新值的映射中。如果键已经在地图中,只需将新值添加到列表中。

def hash = [:] 
new File("test.data").eachLine { String line -> 
    def (key,value) = line.split(/\|/) 
    hash.get(key, []) << value 
} 

println hash 

它打印出如下图:

[key1:[value1, value2, value3], key2:[value4, value5]] 

无需保持currentKey轨道。

编辑:这是用Groovy编写的,但在其他语言中应该以相似的方式实现。 hash.get()返回键的值或提供的默认值(在上面的代码片段中是一个空列表),而左移(<<)操作符将某些内容添加到列表中。