【问题标题】:How to create a dictionary using a single list?如何使用单个列表创建字典?
【发布时间】:2019-08-15 16:15:53
【问题描述】:

我有一份来自我所在国家/地区的报纸网站的网址和标题列表。举个一般的例子:

x = ['URL1','news1','news2','news3','URL2','news1','news2','URL3','news1']

每个 URL 元素都有一个相应的“新闻”元素序列,其长度可以不同。在上面的例子中,URL1 有 3 个对应的新闻,而 URL3 只有一个。

有时一个 URL 没有对应的“新闻”元素:

y = ['URL4','news1','news2','URL5','URL6','news1']

我可以轻松找到每个 URL 索引和每个 URL 的“新闻”元素。

我的问题是:是否可以将此列表转换为字典,其中 URL 元素是键,“新闻”元素是列表/元组值?

预期输出

z = {'URL1':('news1', 'news2', 'news3'),
     'URL2':('news1', 'news2'),
     'URL3':('news1'),
     'URL4':('news1', 'news2'),
     'URL5':(),
     'URL6':('news1')}

我在post 中看到了类似的问题,但它并没有解决我的问题。

【问题讨论】:

  • 请包含您编写的未产生所需输出的代码。
  • 这是可能的,但对于某些函数 foobarbaz,可能没有像 dict(foo(bar(baz(x)))) 这样特别优雅的东西。
  • 你在生成x吗?如果是这样,一定有更好的方法来做到这一点。
  • @DeepSpace 我正在使用 Selenium 废弃一个网站,尽管以这种方式使用列表更容易使用。但事实并非如此。

标签: python list dictionary


【解决方案1】:

你可以这样做:

>>> y = ['URL4','news1','news2','URL5','URL6','news1']
>>> result = {}
>>> current_url = None
>>> for entry in y:
...     if entry.startswith('URL'):
...         current_url = entry
...         result[current_url] = ()
...     else:
...         result[current_url] += (entry, )
...         
>>> result
{'URL4': ('news1', 'news2'), 'URL5': (), 'URL6': ('news1',)}

【讨论】:

  • 你可以使用deafultdict(list)来保存至少4行。如果您知道需要添加新项目,我不确定您为什么选择使用元组
  • @DeepSpace,OP 想要元组,所以他们来了!我最初使用的是列表,但后来编辑了代码以使用元组。至于defaultdict - 绝对;我总是忘记它。
  • @DeepSpace 我明白你关于使用元组的观点。我重新排列了 ForceBru 的答案以适合数组。
【解决方案2】:

您可以使用 itertools.groupbykey 函数来识别 URL:

from itertools import groupby
def _key(url):
    return url.startswith("URL") #in the body of _key, write code to identify a URL

data = ['URL1','news1','news2','news3','URL2','news1','news2','URL3','news1', 'URL4','news1','news2','URL5','URL6','news1']
new_d = [list(b) for _, b in groupby(data, key=_key)]
grouped = [[new_d[i], tuple(new_d[i+1])] for i in range(0, len(new_d), 2)]
result = dict([i for [*c, a], b in grouped for i in [(i, ()) for i in c]+[(a, b)]])

输出:

{
 'URL1': ('news1', 'news2', 'news3'), 
 'URL2': ('news1', 'news2'), 
 'URL3': ('news1',), 
 'URL4': ('news1', 'news2'), 
 'URL5': (), 
 'URL6': ('news1',)
}

【讨论】:

    【解决方案3】:

    您可以只使用列表中 URL 键的索引并获取索引之间的内容并分配给第一个

    像这样:

    x = ['URL1','news1','news2','news3','URL2','news1','news2','URL3','news1']
    urls = [x.index(y) for y in x if 'URL' in y]
    adict = {}
    for i in range(0, len(urls)):
        if i == len(urls)-1:
            adict[x[urls[i]]] = x[urls[i]+1:len(x)]
        else:
            adict[x[urls[i]]] = x[urls[i]+1:urls[i+1]]
    print(adict)
    

    输出:

    {'URL1': ['news1', 'news2', 'news3'], 'URL2': ['news1', 'news2'], 'URL3': ['news1']}
    

    【讨论】:

    • if 'URL' in y 对于像http://mytinyURL.com 这样的字符串也将是True,这不是您想要的。
    • @jjramsey 但这不在他的列表中。
    • 没错,但 'news1''news2' 等项目显然是可能包含几乎任意文本的项目的占位符,包括包含字符 'URL' 的字符串。
    • @jjramsey 他显然可以根据他的用例对其进行修改。这就像说如果“Cat”是 URL 之一,则此特定代码将不起作用——它是任意的。我们的想法是使用索引并找到有关 url 的独特之处以便能够获取它们。
    • @jjramsey 我应该指出news 项目中没有'URL'
    【解决方案4】:

    more-itertools library 包含一个函数 split_before(),它为此目的非常方便:

    {s[0]: tuple(s[1:]) for s in mt.split_before(x, lambda e: e.startswith('URL'))}
    

    我认为这比之前发布的答案中的任何其他方法都干净,但它确实引入了外部依赖项(除非您重新实现该函数),这使得它不适用于所有情况。

    如果您的实际用例涉及真实的 URL 或其他内容,而不是 URL# 形式的字符串,那么只需将 lambda e: e.startswith('URL') 替换为您可以用来选择除值元素之外的关键元素的任何函数。

    【讨论】:

      【解决方案5】:

      使用groupby 的另一种解决方案,单线:

      x = ['URL1','news1','news2','news3','URL2','news1','news2','URL3','news1', 'URL4','news1','news2','URL5','URL6','news1']
      
      from itertools import groupby
      
      out = {k: tuple(v) for _, (k, *v) in groupby(x, lambda k, d={'g':0}: (d.update(g=d['g']+1), d['g']) if k.startswith('URL') else (None, d['g']))}
      
      from pprint import pprint
      pprint(out)
      

      打印:

      {'URL1': ('news1', 'news2', 'news3'),
       'URL2': ('news1', 'news2'),
       'URL3': ('news1',),
       'URL4': ('news1', 'news2'),
       'URL5': (),
       'URL6': ('news1',)}
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2021-06-16
        • 2018-09-17
        • 1970-01-01
        • 2022-08-03
        • 1970-01-01
        • 1970-01-01
        • 2017-06-10
        • 2019-07-28
        相关资源
        最近更新 更多