【问题标题】:Python: Consolidating sublists; spanning multiple linesPython:合并子列表;跨越多行
【发布时间】:2018-02-06 11:19:38
【问题描述】:

我有一个看起来像这样的列表:

[u'https://www.microsoft.com']
[u'https://www.microsoft.com']
[u'https://products.office.com/en-us/home']
[u'https://www.microsoft.com/en-us/windows/']
[u'https://www.microsoft.com/surface/en-us']
[u'https://www.xbox.com/en-us']

我想稍微清理一下输出,对值进行排序,删除重复的条目,等等。但在它的当前格式中,它不是将每个值作为一个完整的单个元素进行操作,而是对单个字符(即,只是一串单个字母)进行操作。我得到的只是无意义的文本字符串。

所以基本上,我想将所有子列表合并到一个列表中,在一行上,采用以下(常规)格式:

['https://www.microsoft.com', 'https://www.microsoft.com', 'https://products.office.com/en-us/home', 'https://www.microsoft.com/en-us/windows/', 'https://www.microsoft.com/surface/en-us', 'https://www.xbox.com/en-us']

我是 Python 新手,所以我可能遗漏了一些东西(或在某些时候使用了不正确的术语),但这(以及方括号的位置)是我认为这被视为列表的原因(和/或多个子列表);如果我用print(type(links)) 替换print(links),我会得到以下输出:

<type 'list'>
<type 'list'>
<type 'list'>
<type 'list'>
<type 'list'>
<type 'list'>

定义links 的原始代码如下所示:

class LinkParser(HTMLParser):
  def handle_starttag(self, tag, attrs):
    links = []
    if tag == 'a':
      for attr in attrs:
        if attr[0] == 'href':
          links.append(attr[1])
          print(links)

【问题讨论】:

  • print(my_list) 的输出看起来不像列表...
  • 你能给出type(my_list)的输出吗?
  • 你可能想要 list(set([el[0] for el in my_list]))。
  • @hiroprotagonist 因为换行符?
  • 换行符,没有逗号,外部列表周围缺少括号。

标签: python python-3.x list nested-lists sublist


【解决方案1】:

看起来您在 my_list 中有一个列表列表。如果是这样

l = [['https://www.microsoft.com'],
['https://www.microsoft.com'],
['https://products.office.com/en-us/home'],
['https://www.microsoft.com/en-us/windows/'],
['https://www.microsoft.com/surface/en-us'],
['https://www.xbox.com/en-us']]

res = []
for i in l:
    if i[0] not in res:
        res.append(i[0])
print(res)

输出:

['https://www.microsoft.com', 'https://products.office.com/en-us/home', 'https://www.microsoft.com/en-us/windows/', 'https://www.microsoft.com/surface/en-us', 'https://www.xbox.com/en-us']

【讨论】:

    【解决方案2】:

    toolz.concat 非常高效(作为惰性函数)并且非常适合此类任务。

    from toolz import concat
    
    lst = [['https://www.microsoft.com'],
    ['https://www.microsoft.com'],
    ['https://products.office.com/en-us/home'],
    ['https://www.microsoft.com/en-us/windows/'],
    ['https://www.microsoft.com/surface/en-us'],
    ['https://www.xbox.com/en-us']]
    
    list(concat(lst))  # for a sorted list, replace list with sorted
    
    # ['https://www.microsoft.com',
    #  'https://www.microsoft.com',
    #  'https://products.office.com/en-us/home',
    #  'https://www.microsoft.com/en-us/windows/',
    #  'https://www.microsoft.com/surface/en-us',
    #  'https://www.xbox.com/en-us']
    

    或者,如果你想要一套:

    set(concat(lst))
    
    # {'https://products.office.com/en-us/home',
    #  'https://www.microsoft.com',
    #  'https://www.microsoft.com/en-us/windows/',
    #  'https://www.microsoft.com/surface/en-us',
    #  'https://www.xbox.com/en-us'}
    

    如果您没有toolz,您可以改用下面的。 toolz 经常为隐藏在其他库中的一些常见的难以找到的函数提供方便的访问。

    import itertools
    itertools.chain.from_iterable(...)
    

    【讨论】:

    • toolz 不在标准 python 库中。您可能想添加一个指向库的链接以及如何安装它。
    • @hiroprotagonist,更新为 itertools 替代品。 toolz 通常只提供语法糖或常用工具的快捷方式。
    • 没有反对tools。我只是认为如果您添加一些有关图书馆的信息,答案会更完整。
    • 我没用过toolz,但我试过你提到的setitertools技术。
    【解决方案3】:
    data = [['https://www.microsoft.com'],
    ['https://www.microsoft.com'],
    ['https://products.office.com/en-us/home'],
    ['https://www.microsoft.com/en-us/windows/'],
    ['https://www.microsoft.com/surface/en-us'],
    ['https://www.xbox.com/en-us']]
    
    from itertools import chain
    
    new_list = list(dict.fromkeys(chain.from_iterable(data)))
    
    print(new_list)
    >>>
    ['https://www.microsoft.com',
     'https://products.office.com/en-us/home',
     'https://www.microsoft.com/en-us/windows/',
     'https://www.microsoft.com/surface/en-us',
     'https://www.xbox.com/en-us']
    

    【讨论】:

      【解决方案4】:

      您没有一个列表,而是包含一个元素的 6 个列表。如果你想收藏 所有这些都放在一个没有重复的项目中我建议你使用 set:

      class MyHTMLParser(HTMLParser):
          def handle_starttag(self, tag, attrs):
              my_set = set()
              if tag == 'a':
                  for attrs in attrs:
                      if attrs[0] == 'href' and '.' in attrs[1]:
                          my_set.add(attrs[1])
              print(sorted(my_set))
      

      ...我无法对此进行测试;你可能需要稍微调整一下。

      【讨论】:

      • 同样的问题。输出看起来像这样的几行:['.', '/', ':', 'c', 'f', 'h', 'i', 'm', 'o', 'p', 'r', 's', 't', 'w']
      • 真的吗?因为:my_set = set(); my_set.add('hello') 给了{'hello'}...
      • 那是使用.update。使用.add,输出看起来与问题中的相同。我的脑袋疼。
      • 你会在另一个循环中使用所有这些吗?
      • 不。没有更多的循环。我什至尝试省略当前的 for 循环,我认为这会起作用,但没有输出。
      【解决方案5】:

      好的,我想通了:

      1. 有问题的对象/列表(即 links)需要在定义它的函数和/或类的范围之外进行初始化(即代码块项目附加到它的地方)。它可以在之前,也可以在之后;只要它首先被解释。

      2. 这同样适用于调用 print() 语句(关于范围),但它应该最后解释(在调用设置它的函数和/或类之后)。


      例如:

      输入:

      class LinkParser(HTMLParser):
        def handle_starttag(self, tag, attrs):
          if tag == 'a':
            for attr in attrs:
              if attr[0] == 'href':
                links.append(attr[1])
      
      links = []
      LinkParser().feed(html)
      print(links)
      

      输出:

      [u'@987654321@', u'@987654322@', u'@987654323@', u'@987654324@', u'@987654325@', u'@987654326@']

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2013-04-29
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多