【问题标题】:How to group, sort, count records and output results如何对记录进行分组、排序、计数和输出结果
【发布时间】:2013-02-28 01:31:59
【问题描述】:

我正在尝试创建一个执行以下操作的 python 脚本:

表(dbf 或 csv-我都可以创建)总是只有 4 条记录。第二列(Let)将始终按 a、b、c、d 排序。第 1 列(Num)总是有 0-10 之间的数字,但频率和顺序会有所不同。输出需要按 Num 排序和分组,首先输出最小的数字。如果第一列中的数字出现一次,则只输出对应的字母。如果一个数字出现两次(即两行具有相同的数字),则输出每个对应的字母,并在它们之间加上一个“and”。如果数字出现两次以上,则输出每个字母,它们之间有一个逗号,最后一个字母之前有一个“和”。每个出现的字母组都有自己的输出行。

基本上是对 4 个选项中的 1 个进行排序、分组和输出:

“无数据”
1 个字母本身
2个字母用“and”隔开
3 个字母,用逗号隔开,最后一个字母前加一个“and”。

以下是名为 soils_no.dbf 的表的不同版本及其所需的输出,具体取决于输入。

Num.......让
0........一个
0......b
0.......c
0........d
打印“无数据”

Num.......让
8........一个
8...............b
2.......c
8........d
打印 c
打印 a、b 和 d

Num.......让
4.......一个
1.................b
7.......c
3.......d
打印 b
打印 d
打印一个
打印 c

Num.......让
3.......一个
3.............b
10........c
1........d
打印 d
打印 a 和 b
打印 c

Num.......让
10.......一个
10.......b
10.......c
10........d
打印 a、b、c 和 d

我知道如何循环并放入逗号和“and”,但我不知道如何分组和排序。 使用 python 2.7 执行此操作。

顺便说一句,我正在尝试学习 python,所以请解释一下代码的含义。我学得越多,就越不依赖陌生人的善意。

提前致谢。

【问题讨论】:

    标签: sorting python-2.7 group-by


    【解决方案1】:

    下面讨论。

    from collections import defaultdict
    
    def pretty_print_lst(lst):
        if not lst:
            return ""
        elif len(lst) == 1:
            return lst[0]
        elif len(lst) == 2:
            # Join together two letters using " and " as the join.
            return " and ".join(lst)
        else:
            # Use a "list slice" to join all in the list but the last item,
            # using ", " as the join, then append " and " and append the
            # last item.  Last item is indexed with -1, which always works no
            # matter how many or few items are in the list.
            return ", ".join(lst[:-1]) + " and " + lst[-1]
    
    def print_rec(seq):
        # group according to counts
        d = defaultdict(list)
        for row in seq:
            n, letter = row  # get count and letter from the row
            d[n] += letter  # append letter to that count list
    
        # get a list of (key, value) pairs
        # so the list entries are: (count, list_of_letters)
        results = list(d.items())
        results.sort()
        if len(results) == 1 and results[0][0] == 0:
            # if all 4 letters have a count of 0, 
            print("No data")
        else:
            for count, lst in results:
                s = pretty_print_lst(lst)
                print(s)
    
    lst = [ (8, 'a'), (8, 'b'), (2, 'c'), (8, 'd')]
    print_rec(lst)
    

    我们使用字典来收集具有相同计数的项目。这是一个“默认字典”;每当我们引用一个不存在的键时,它就会被创建,在这种情况下是一个空列表。所以我们可以只追加值,字典是否为空并不重要。

    然后我们收集非零项目并制作一个列表,然后漂亮地打印列表以匹配您想要的格式。

    如果您有任何问题,请随时提出。

    【讨论】:

    • 我的样本数据可能有点误导。零可以分散在上述任何表中,并且它的值像其他任何值一样返回,除非您将所有 4 条记录都设为零,所以我真的不想去掉零,如果所有记录都打印一个单独的响应为零。不确定这是否会更改代码。另外,表是 dbf 还是 csv 是否重要?
    • 此外,有时为了简洁起见(想读小说的人),我可能会省略重要的细节(尽管当时它们似乎并不重要,因为我认为我可以修改文本)。把第四张桌子拿下来。输出实际上看起来更像:“字母 d 有 1 个订单。字母 a 和 b 各有 3 个订单。字母 c 有 10 个订单。”表 1 会输出如下内容:“本周没有订单。”
    • 我已经更改了代码,以便它可以根据您的要求处理零。我还添加了 cmets 来帮助您解决问题。至于对输出文本的更改,您应该编辑代码并按照您想要的方式进行输出。我相信您可以弄清楚如何进行所需的更改,我会回答问题。
    • 如果第二列(Let)包含一个或多个单词而不是一个字母,我该如何修改这个脚本? (比如 a 是苹果,b 是香蕉等)。 @steveha
    • 我知道你的脚本做了什么(这在概念上很有帮助),但我不知道如何根据我的情况修改它。首先,数据位于一个 csv 文件中,看起来与原始帖子中描述的内容相似(标题,4 行数据)。它不是您在代码中的列表。其次,我还有一些与此非常相似的其他数据,但第二列包含单词(通常是 1 或两个单词) 此代码在列中的每个字母之后放置一个逗号,而不是在第二列中的所有信息之后。谢谢你的帮助。我非常感谢 cmets 解释代码。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-08-08
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多