【问题标题】:Generating a .CSV with Several Columns - Use a Dictionary?生成具有多列的 .CSV - 使用字典?
【发布时间】:2012-11-08 04:12:17
【问题描述】:

我正在编写一个脚本来查看我的库存,将其与所有可能库存项目的主列表进行比较,并告诉我我缺少哪些项目。我的目标是一个 .csv 文件,其中第一列包含一个唯一的键整数,然后其余几列将具有与该键相关的数据。例如,我的最终目标 .csv 文件的三行 sn-p 可能如下所示:

100001,apple,fruit,medium,12,red
100002,carrot,vegetable,medium,10,orange
100005,radish,vegetable,small,10,red

这方面的数据来自几个来源。第一,对 API 服务器的查询为我提供了库存中物品的键列表。第二,我将 .csv 文件读入一个字典,该字典将所有可能键的键与项目名称相匹配。此 .csv 文件前 5 行的 sn-p 可能如下所示:

100001,apple
100002,carrot
100003,pear
100004,banana
100005,radish

请注意,我的库存列表中的任何键将如何在这两个列 .csv 文件中找到,该文件提供了所有键及其对应的项目名称,并且此列表减去我手头的库存会产生我正在寻找的东西(即我需要获得的库存)。

到目前为止,我可以获得一个 .csv 文件,其中仅包含我在库存中没有的项目的键和项目名称。像这样给出手头的库存清单:

100003,100004

生成的 .csv 文件的 sn-p 如下所示:

100001,apple
100002,carrot
100005,radish

这意味着我的库存中有梨和香蕉(因此它们不在此 .csv 文件中。)

为了得到这个,我有一个函数可以在给定项目 id 时获取项目名称,如下所示:

def getNames(id_to_name, ids):
    return [id_to_name[id] for id in ids]

然后是一个函数,它从我的库存服务器 API 调用中将键列表作为整数提供,该调用返回一个列表,我已经像这样运行这个函数:

invlist = ServerApiCallFunction(AppropriateInfo)

第三个函数将此 invlist 作为其输入,并返回一个包含键(项目 ID)和我没有的项目名称的字典。它还将这个 dict 的信息写入 .csv 文件。我正在使用 set1 - set2 方法来执行此操作。它看起来像这样:

def InventoryNumbers(inventory):
    with open(csvfile,'w') as c:
        c.write('InvName' + ',InvID' + '\n')
    missinginvnames = []
    with open("KeyAndItemNameTwoColumns.csv","rb") as fp:
        reader = csv.reader(fp, skipinitialspace=True)
        fp.readline() # skip header
        invidsandnames = {int(id): str.upper(name) for id, name in reader}
    invids = set(invidsandnames.keys())
    invnames = set(invidsandnames.values())
    invonhandset = set(inventory)
    missinginvidsset = invids - invonhandset
    missinginvids = list(missinginvidsset)
    missinginvnames = getNames(invidsandnames, missinginvids)
    missinginvnameswithids = dict(zip(missinginvnames, missinginvids))
    print missinginvnameswithids
    with open(csvfile,'a') as c:
        for invname, invid in missinginvnameswithids.iteritems():
            c.write(invname + ',' + str(invid) + '\n')

    return missinginvnameswithids

然后我这样称呼:

InventoryNumbers(invlist)

有了这个解释,现在开始我的问题。我想通过添加其他列来扩展此输出 .csv 文件中的数据。这方面的数据将从另一个 .csv 文件中提取,其中的 sn-p 如下所示:

100001,fruit,medium,12,red
100002,vegetable,medium,10,orange
100003,fruit,medium,14,green
100004,fruit,medium,12,yellow
100005,vegetable,small,10,red

注意这不包含项目名称(所以我必须从一个不同的 .csv 文件中提取它,该文件只有两列键和项目名称)但它确实使用相同的键。我正在寻找一种方法来引入这些额外信息,以便我的最终 .csv 文件不仅会告诉我我没有库存的物品的密钥(即物品 ID)和物品名称,而且还会有类型、大小、数字和颜色列。

我看过的一个选项是集合中的defaultdict 作品,但我不确定这是否是完成我想做的事情的最佳方式。如果我确实使用了这种方法,我不确定我将如何调用它来达到我想要的结果。如果其他方法更简单,我当然也愿意尝试。

如何获取我在库存中没有的项目的键和相应项目名称的字典,并将这些额外信息添加到其中,以便我可以将其全部输出到 .csv 文件?

编辑:当我输入此内容时,我突然想到,我可以通过创建一个新的单个 .csv 文件来简化自己的工作,该文件的日期格式为键、项目名称、类型、大小、数字、颜色(基本上只是将项目名称列复制到已经包含每个键的其他信息的 .csv 中。)这样我只需要从一个 .csv 文件而不是两个文件中绘制。但是,即使我这样做了,我将如何仅根据那些不在库存中的物品的键来制作我想要的 .csv 文件?

回答:我发布了另一个问题here,关于如何实施我接受的解决方案(因为它给了我一个值错误,因为我的 dict 值是字符串而不是开头的集合),我最终决定我想要一个列表而不是一组(以保留顺序。)我还最终将带有项目名称的列添加到包含所有其他数据的 .csv 文件中,这样我只需要从一个 .csv 文件中提取。也就是说,这部分代码现在的样子如下:

MyDict = {}
infile = open('FileWithAllTheData.csv', 'r')
for line in infile.readlines():
    spl_line = line.split(',')
    if int(spl_line[0]) in missinginvids: #note that this is the list I was using as the keys for my dict which I was zipping together with a corresponding list of item names to make my dict before.
        MyDict.setdefault(int(spl_line[0]), list()).append(spl_line[1:])
print MyDict

【问题讨论】:

  • 来自 perl 背景,我正在学习 python。但是您的问题看起来非常适合 Perl。您可以创建所需信息的哈希值,然后仅使用 print 语句将该哈希值写入 csv。很简单。除此之外,如果您想做一些更高级的事情,那么 perl 的 Text::CSV 和 DBD::CSV 模块将足以满足您的需要。 Perl 以字符串和文本操作而闻名,我曾多次使用 perl 中的 CSV 文件。为工作使用正确的工具。
  • 很公平,你可能是对的——Perl 可能是完成这项工作的更好工具。不过,对我来说,我对编程知之甚少,而且我只知道 Python,所以我想我会坚持下去。也就是说,如果其他人读到这篇文章并且他们是比我更有经验的程序员,他们可能应该研究基于 Perl 的解决方案。

标签: python csv dictionary set


【解决方案1】:

听起来你需要的是一个将整数映射到集合的字典,即,

MyDict = {100001: set([apple]), 100002: set([carrot])}

您可以使用更新添加:

MyDict[100001].update([fruit])

这会给你:{100001: set([apple, fruit]), 100002: set([carrot])}

另外,如果你有胡萝卜的属性列表...[vegetable,orange]

你可以说MyDict[100002].update([vegetable, orange])

然后得到:{100001: set([apple, fruit]), 100002: set([carrot, vegetable, orange])}

这能回答你的问题吗?

编辑:

读入 CSV...

infile = open('MyFile.csv', 'r')
for line in infile.readlines():
    spl_line = line.split(',')
    if int(spl_line[0]) in MyDict.keys():
        MyDict[spl_line[0]].update(spl_line[1:])

【讨论】:

  • 我们已经接近了 :) 它留下的两个问题是 1) 我将如何从 .csv 文件中读取具有各种数据列的数据,以便我只能读取MyDict 中键的数据 2) 我如何将这些列表拆分成几部分并制作我的最终结果 .csv 文件?
  • 我在上面所做的编辑将用您正在阅读的文件中的任何内容替换当前的 Dict 行。至于写成 CSV,我想如果你在谷歌周围挖掘,你可以找到答案。
  • 现在我们已经到了某个地方!为什么使用 dict.update 而不是某种 dict.extend 或 dict.append?更新不会删除以前的数据(所以在我的情况下它会删除项目名称)? docs.python.org/2/library/…
  • 会的,你可以做的另一件事是MyDict[spl_line[0]].extend(spl_line[1:])
  • 我已经更新了这个答案,一个将整数映射到SETS的字典实际上就是你想要的
【解决方案2】:

这不是问题的答案,但这是简化当前代码的一种可能方法。

这个:

invids = set(invidsandnames.keys())
invnames = set(invidsandnames.values())
invonhandset = set(inventory)
missinginvidsset = invids - invonhandset
missinginvids = list(missinginvidsset)
missinginvnames = getNames(invidsandnames, missinginvids)
missinginvnameswithids = dict(zip(missinginvnames, missinginvids))

可以替换为:

invonhandset = set(inventory)
missinginvnameswithids = {k: v for k, v in invidsandnames.iteritems() if k in in inventory}

或者:

invonhandset = set(inventory)
for key in invidsandnames.keys():
    if key not in invonhandset:
        del invidsandnames[key]
missinginvnameswithids = invidsandnames

【讨论】:

  • 我已经弄乱了那种风格(使用 iteritems)和 set1 - set2 风格,基本上只是选择了我设法首先开始工作的那个。我会回顾一下并再次尝试使用 iteritems 样式,因为它确实更小更整洁。
  • 它也不需要创建任何中间集。它应该更有效率。我还添加了另一种方法。
【解决方案3】:

您是否考虑过制作一个临时 RDB(python 已嵌入 sqlite support)并且对于合理数量的项目,我认为您不会遇到性能问题。

我会将每个 CSV 文件和来自 web-api 的结果转换成一个表格(每个数据源一个表格)。然后,您可以使用一些 SQL 查询 + 连接来做任何您想做的事情。获得所需数据后,您可以将其转储回 CSV。

【讨论】:

  • 我当然不反对这个想法——我并不关心我需要使用什么方法来获得所需的 .csv 输出——但我不确定这会是什么样子案子。我承认我一直使用 .csv 文件作为输入的部分原因是为了避免使用 SQL,因为我对它不是很熟悉。所需的查询(在 Python 中)可能是什么样的?
  • @Qanthelas python 基本上会将 SQL 查询直接传递给 sqlite。这是另一罐蠕虫,但我认为值得打开。
猜你喜欢
  • 2019-10-05
  • 1970-01-01
  • 2018-03-10
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-06-15
  • 2014-04-06
相关资源
最近更新 更多