标签归档:list

字典元组列表

问题:字典元组列表

这是我目前在Python中将元组列表转换为字典的方式:

l = [('a',1),('b',2)]
h = {}
[h.update({k:v}) for k,v in l]
> [None, None]
h
> {'a': 1, 'b': 2}

有没有更好的办法?似乎应该有一种做法。

Here’s how I’m currently converting a list of tuples to dictionary in Python:

l = [('a',1),('b',2)]
h = {}
[h.update({k:v}) for k,v in l]
> [None, None]
h
> {'a': 1, 'b': 2}

Is there a better way? It seems like there should be a one-liner to do this.


回答 0

只需dict()直接调用元组列表

>>> my_list = [('a', 1), ('b', 2)]
>>> dict(my_list)
{'a': 1, 'b': 2}

Just call dict() on the list of tuples directly

>>> my_list = [('a', 1), ('b', 2)]
>>> dict(my_list)
{'a': 1, 'b': 2}

回答 1

dict构造函数接受输入的完全一样,你把它(键/值元组)。

>>> l = [('a',1),('b',2)]
>>> d = dict(l)
>>> d
{'a': 1, 'b': 2}

文档中

例如,所有这些都返回等于{“ one”:1,“ two”:2}的字典:

dict(one=1, two=2)
dict({'one': 1, 'two': 2})
dict(zip(('one', 'two'), (1, 2)))
dict([['two', 2], ['one', 1]])

The dict constructor accepts input exactly as you have it (key/value tuples).

>>> l = [('a',1),('b',2)]
>>> d = dict(l)
>>> d
{'a': 1, 'b': 2}

From the documentation:

For example, these all return a dictionary equal to {“one”: 1, “two”: 2}:

dict(one=1, two=2)
dict({'one': 1, 'two': 2})
dict(zip(('one', 'two'), (1, 2)))
dict([['two', 2], ['one', 1]])

回答 2

具有dict理解力:

h = {k:v for k,v in l}

With dict comprehension:

h = {k:v for k,v in l}

回答 3

似乎每个人都假定元组列表在键和值之间具有一对一的映射关系(例如,它没有字典的重复键)。由于这是在该主题上搜索的第一个问题,因此我针对一个更常见的情况发布了答案,在这种情况下,我们必须处理重复项:

mylist = [(a,1),(a,2),(b,3)]    
result = {}
for i in mylist:  
   result.setdefault(i[0],[]).append(i[1])
print(result)
>>> result = {a:[1,2], b:[3]}

It seems everyone here assumes the list of tuples have one to one mapping between key and values (e.g. it does not have duplicated keys for the dictionary). As this is the first question coming up searching on this topic, I post an answer for a more general case where we have to deal with duplicates:

mylist = [(a,1),(a,2),(b,3)]    
result = {}
for i in mylist:  
   result.setdefault(i[0],[]).append(i[1])
print(result)
>>> result = {a:[1,2], b:[3]}

将Python字符串格式化与列表一起使用

问题:将Python字符串格式化与列表一起使用

s在Python 2.6.5中构造了一个字符串,该字符串将具有不同数量的%s令牌,这些令牌与list中的条目数匹配x。我需要写出格式化的字符串。以下内容不起作用,但表示我要执行的操作。在此示例中,有三个%s标记,并且列表具有三个条目。

s = '%s BLAH %s FOO %s BAR'
x = ['1', '2', '3']
print s % (x)

我希望输出字符串为:

1 BLAH 2 FOO 3 BAR

I construct a string s in Python 2.6.5 which will have a varying number of %s tokens, which match the number of entries in list x. I need to write out a formatted string. The following doesn’t work, but indicates what I’m trying to do. In this example, there are three %s tokens and the list has three entries.

s = '%s BLAH %s FOO %s BAR'
x = ['1', '2', '3']
print s % (x)

I’d like the output string to be:

1 BLAH 2 FOO 3 BAR


回答 0

print s % tuple(x)

代替

print s % (x)
print s % tuple(x)

instead of

print s % (x)

回答 1

您应该看一下python 的format方法。然后,您可以像这样定义格式字符串:

>>> s = '{0} BLAH BLAH {1} BLAH {2} BLAH BLIH BLEH'
>>> x = ['1', '2', '3']
>>> print s.format(*x)
'1 BLAH BLAH 2 BLAH 3 BLAH BLIH BLEH'

You should take a look to the format method of python. You could then define your formatting string like this :

>>> s = '{0} BLAH BLAH {1} BLAH {2} BLAH BLIH BLEH'
>>> x = ['1', '2', '3']
>>> print s.format(*x)
'1 BLAH BLAH 2 BLAH 3 BLAH BLIH BLEH'

回答 2

在此资源页面之后,如果x的长度变化,我们可以使用:

', '.join(['%.2f']*len(x))

为列表中的每个元素创建一个占位符x。这是示例:

x = [1/3.0, 1/6.0, 0.678]
s = ("elements in the list are ["+', '.join(['%.2f']*len(x))+"]") % tuple(x)
print s
>>> elements in the list are [0.33, 0.17, 0.68]

Following this resource page, if the length of x is varying, we can use:

', '.join(['%.2f']*len(x))

to create a place holder for each element from the list x. Here is the example:

x = [1/3.0, 1/6.0, 0.678]
s = ("elements in the list are ["+', '.join(['%.2f']*len(x))+"]") % tuple(x)
print s
>>> elements in the list are [0.33, 0.17, 0.68]

回答 3

这是一行代码。一个临时的答案,使用带有print()的format来迭代列表。

怎么样(Python 3.x):

sample_list = ['cat', 'dog', 'bunny', 'pig']
print("Your list of animals are: {}, {}, {} and {}".format(*sample_list))

在此处阅读有关使用format()的文档。

Here is a one liner. A little improvised answer using format with print() to iterate a list.

How about this (python 3.x):

sample_list = ['cat', 'dog', 'bunny', 'pig']
print("Your list of animals are: {}, {}, {} and {}".format(*sample_list))

Read the docs here on using format().


回答 4

由于我刚刚学到了这个很酷的东西(从格式字符串中索引到列表中),所以我添加了这个老问题。

s = '{x[0]} BLAH {x[1]} FOO {x[2]} BAR'
x = ['1', '2', '3']
print (s.format (x=x))

输出:

1 BLAH 2 FOO 3 BAR

但是,我仍然没有弄清楚如何进行切片(在格式字符串'"{x[2:4]}".format...中),并且很想弄清楚是否有人有想法,但是我怀疑您根本无法做到这一点。

Since I just learned about this cool thing(indexing into lists from within a format string) I’m adding to this old question.

s = '{x[0]} BLAH {x[1]} FOO {x[2]} BAR'
x = ['1', '2', '3']
print (s.format (x=x))

Output:

1 BLAH 2 FOO 3 BAR

However, I still haven’t figured out how to do slicing(inside of the format string '"{x[2:4]}".format...,) and would love to figure it out if anyone has an idea, however I suspect that you simply cannot do that.


回答 5

这是一个有趣的问题!处理可变长度列表的另一种方法是构建一个充分利用该.format方法和列表拆包的功能。在下面的示例中,我不使用任何特殊的格式,但是可以轻松地对其进行更改以满足您的需求。

list_1 = [1,2,3,4,5,6]
list_2 = [1,2,3,4,5,6,7,8]

# Create a function that can apply formatting to lists of any length:
def ListToFormattedString(alist):
    # Create a format spec for each item in the input `alist`.
    # E.g., each item will be right-adjusted, field width=3.
    format_list = ['{:>3}' for item in alist] 

    # Now join the format specs into a single string:
    # E.g., '{:>3}, {:>3}, {:>3}' if the input list has 3 items.
    s = ','.join(format_list)

    # Now unpack the input list `alist` into the format string. Done!
    return s.format(*alist)

# Example output:
>>>ListToFormattedString(list_1)
'  1,  2,  3,  4,  5,  6'
>>>ListToFormattedString(list_2)
'  1,  2,  3,  4,  5,  6,  7,  8'

This was a fun question! Another way to handle this for variable length lists is to build a function that takes full advantage of the .format method and list unpacking. In the following example I don’t use any fancy formatting, but that can easily be changed to suit your needs.

list_1 = [1,2,3,4,5,6]
list_2 = [1,2,3,4,5,6,7,8]

# Create a function that can apply formatting to lists of any length:
def ListToFormattedString(alist):
    # Create a format spec for each item in the input `alist`.
    # E.g., each item will be right-adjusted, field width=3.
    format_list = ['{:>3}' for item in alist] 

    # Now join the format specs into a single string:
    # E.g., '{:>3}, {:>3}, {:>3}' if the input list has 3 items.
    s = ','.join(format_list)

    # Now unpack the input list `alist` into the format string. Done!
    return s.format(*alist)

# Example output:
>>>ListToFormattedString(list_1)
'  1,  2,  3,  4,  5,  6'
>>>ListToFormattedString(list_2)
'  1,  2,  3,  4,  5,  6,  7,  8'

回答 6

与@neobot的答案相同,但更加现代和简洁。

>>> l = range(5)
>>> " & ".join(["{}"]*len(l)).format(*l)
'0 & 1 & 2 & 3 & 4'

The same as @neobot’s answer but a little more modern and succinct.

>>> l = range(5)
>>> " & ".join(["{}"]*len(l)).format(*l)
'0 & 1 & 2 & 3 & 4'

回答 7

x = ['1', '2', '3']
s = f"{x[0]} BLAH {x[1]} FOO {x[2]} BAR"
print(s)

输出是

1 BLAH 2 FOO 3 BAR
x = ['1', '2', '3']
s = f"{x[0]} BLAH {x[1]} FOO {x[2]} BAR"
print(s)

The output is

1 BLAH 2 FOO 3 BAR

一对单对

问题:一对单对

通常,我发现需要成对处理列表。我想知道哪种方法是有效的pythonic方法,并在Google上找到了它:

pairs = zip(t[::2], t[1::2])

我认为这已经足够好用了,但是在最近涉及成语与效率的讨论之后,我决定进行一些测试:

import time
from itertools import islice, izip

def pairs_1(t):
    return zip(t[::2], t[1::2]) 

def pairs_2(t):
    return izip(t[::2], t[1::2]) 

def pairs_3(t):
    return izip(islice(t,None,None,2), islice(t,1,None,2))

A = range(10000)
B = xrange(len(A))

def pairs_4(t):
    # ignore value of t!
    t = B
    return izip(islice(t,None,None,2), islice(t,1,None,2))

for f in pairs_1, pairs_2, pairs_3, pairs_4:
    # time the pairing
    s = time.time()
    for i in range(1000):
        p = f(A)
    t1 = time.time() - s

    # time using the pairs
    s = time.time()
    for i in range(1000):
        p = f(A)
        for a, b in p:
            pass
    t2 = time.time() - s
    print t1, t2, t2-t1

这些是我计算机上的结果:

1.48668909073 2.63187503815 1.14518594742
0.105381965637 1.35109519958 1.24571323395
0.00257992744446 1.46182489395 1.45924496651
0.00251388549805 1.70076990128 1.69825601578

如果我正确地解释了它们,那应该意味着在Python中实现列表,列表索引和列表切片非常有效。这是令人安慰和意外的结果。

是否有另一种“更好”的成对遍历列表的方式?

请注意,如果列表中元素的数量为奇数,则最后一个元素将不在任何对中。

确保包含所有元素的正确方法是哪种?

我从测试答案中添加了这两个建议:

def pairwise(t):
    it = iter(t)
    return izip(it, it)

def chunkwise(t, size=2):
    it = iter(t)
    return izip(*[it]*size)

结果如下:

0.00159502029419 1.25745987892 1.25586485863
0.00222492218018 1.23795199394 1.23572707176

到目前为止的结果

最pythonic,非常高效:

pairs = izip(t[::2], t[1::2])

最有效且非常pythonic:

pairs = izip(*[iter(t)]*2)

我花了一点时间想知道第一个答案使用了两个迭代器,而第二个答案使用了一个迭代器。

为了处理具有奇数个元素的序列,建议增加原始序列,增加一个元素(None)与之前的最后一个元素配对,这可以通过实现itertools.izip_longest()

最后

请注意,在Python 3.x中,zip()其行为与itertools.izip()itertools.izip() 消失了。

Often enough, I’ve found the need to process a list by pairs. I was wondering which would be the pythonic and efficient way to do it, and found this on Google:

pairs = zip(t[::2], t[1::2])

I thought that was pythonic enough, but after a recent discussion involving idioms versus efficiency, I decided to do some tests:

import time
from itertools import islice, izip

def pairs_1(t):
    return zip(t[::2], t[1::2]) 

def pairs_2(t):
    return izip(t[::2], t[1::2]) 

def pairs_3(t):
    return izip(islice(t,None,None,2), islice(t,1,None,2))

A = range(10000)
B = xrange(len(A))

def pairs_4(t):
    # ignore value of t!
    t = B
    return izip(islice(t,None,None,2), islice(t,1,None,2))

for f in pairs_1, pairs_2, pairs_3, pairs_4:
    # time the pairing
    s = time.time()
    for i in range(1000):
        p = f(A)
    t1 = time.time() - s

    # time using the pairs
    s = time.time()
    for i in range(1000):
        p = f(A)
        for a, b in p:
            pass
    t2 = time.time() - s
    print t1, t2, t2-t1

These were the results on my computer:

1.48668909073 2.63187503815 1.14518594742
0.105381965637 1.35109519958 1.24571323395
0.00257992744446 1.46182489395 1.45924496651
0.00251388549805 1.70076990128 1.69825601578

If I’m interpreting them correctly, that should mean that the implementation of lists, list indexing, and list slicing in Python is very efficient. It’s a result both comforting and unexpected.

Is there another, “better” way of traversing a list in pairs?

Note that if the list has an odd number of elements then the last one will not be in any of the pairs.

Which would be the right way to ensure that all elements are included?

I added these two suggestions from the answers to the tests:

def pairwise(t):
    it = iter(t)
    return izip(it, it)

def chunkwise(t, size=2):
    it = iter(t)
    return izip(*[it]*size)

These are the results:

0.00159502029419 1.25745987892 1.25586485863
0.00222492218018 1.23795199394 1.23572707176

Results so far

Most pythonic and very efficient:

pairs = izip(t[::2], t[1::2])

Most efficient and very pythonic:

pairs = izip(*[iter(t)]*2)

It took me a moment to grok that the first answer uses two iterators while the second uses a single one.

To deal with sequences with an odd number of elements, the suggestion has been to augment the original sequence adding one element (None) that gets paired with the previous last element, something that can be achieved with itertools.izip_longest().

Finally

Note that, in Python 3.x, zip() behaves as itertools.izip(), and itertools.izip() is gone.


回答 0

我最喜欢的方式:

from itertools import izip

def pairwise(t):
    it = iter(t)
    return izip(it,it)

# for "pairs" of any length
def chunkwise(t, size=2):
    it = iter(t)
    return izip(*[it]*size)

当您要配对所有元素时,您显然可能需要一个fillvalue:

from itertools import izip_longest
def blockwise(t, size=2, fillvalue=None):
    it = iter(t)
    return izip_longest(*[it]*size, fillvalue=fillvalue)

My favorite way to do it:

from itertools import izip

def pairwise(t):
    it = iter(t)
    return izip(it,it)

# for "pairs" of any length
def chunkwise(t, size=2):
    it = iter(t)
    return izip(*[it]*size)

When you want to pair all elements you obviously might need a fillvalue:

from itertools import izip_longest
def blockwise(t, size=2, fillvalue=None):
    it = iter(t)
    return izip_longest(*[it]*size, fillvalue=fillvalue)

回答 1

我想说您的初始解决方案pairs = zip(t[::2], t[1::2])是最好的解决方案,因为它最容易阅读(在Python 3中,它会zip自动返回一个迭代器而不是列表)。

为了确保包括所有元素,您可以通过扩展列表None

然后,如果列表中元素的数量为奇数,则最后一对将为(item, None)

>>> t = [1,2,3,4,5]
>>> t.append(None)
>>> zip(t[::2], t[1::2])
[(1, 2), (3, 4), (5, None)]
>>> t = [1,2,3,4,5,6]
>>> t.append(None)
>>> zip(t[::2], t[1::2])
[(1, 2), (3, 4), (5, 6)]

I’d say that your initial solution pairs = zip(t[::2], t[1::2]) is the best one because it is easiest to read (and in Python 3, zip automatically returns an iterator instead of a list).

To ensure that all elements are included, you could simply extend the list by None.

Then, if the list has an odd number of elements, the last pair will be (item, None).

>>> t = [1,2,3,4,5]
>>> t.append(None)
>>> zip(t[::2], t[1::2])
[(1, 2), (3, 4), (5, None)]
>>> t = [1,2,3,4,5,6]
>>> t.append(None)
>>> zip(t[::2], t[1::2])
[(1, 2), (3, 4), (5, 6)]

回答 2

我从小的免责声明开始-不要使用下面的代码。根本不是Pythonic,我只是为了好玩而写。它类似于@ THC4k pairwise函数,但使用iterlambda闭包。它不使用itertools模块,不支持fillvalue。我把它放在这里是因为有人可能会觉得有趣:

pairwise = lambda t: iter((lambda f: lambda: (f(), f()))(iter(t).next), None)

I start with small disclaimer – don’t use the code below. It’s not Pythonic at all, I wrote just for fun. It’s similar to @THC4k pairwise function but it uses iter and lambda closures. It doesn’t use itertools module and doesn’t support fillvalue. I put it here because someone might find it interesting:

pairwise = lambda t: iter((lambda f: lambda: (f(), f()))(iter(t).next), None)

回答 3

就大多数pythonic而言,我想说python源文档中提供食谱(其中一些看起来很像@JochenRitzel提供的答案)可能是您最好的选择;)

def grouper(iterable, n, fillvalue=None):
    "Collect data into fixed-length chunks or blocks"
    # grouper('ABCDEFG', 3, 'x') --> ABC DEF Gxx
    args = [iter(iterable)] * n
    return izip_longest(fillvalue=fillvalue, *args)

As far as most pythonic goes, I’d say the recipes supplied in the python source docs (some of which look a lot like the answers that @JochenRitzel provided) is probably your best bet ;)

def grouper(iterable, n, fillvalue=None):
    "Collect data into fixed-length chunks or blocks"
    # grouper('ABCDEFG', 3, 'x') --> ABC DEF Gxx
    args = [iter(iterable)] * n
    return izip_longest(fillvalue=fillvalue, *args)

On modern python you just have to use zip_longest(*args, fillvalue=fillvalue) according to the corresponding doc page.


回答 4

是否有另一种“更好”的成对遍历列表的方式?

我不能肯定地说,但我对此表示怀疑:任何其他遍历都会包含更多必须解释的Python代码。诸如zip()之类的内置函数是用C编写的,这要快得多。

确保包含所有元素的正确方法是哪种?

检查列表的长度,如果它是奇数(len(list) & 1 == 1),则复制列表并附加一个项目。

Is there another, “better” way of traversing a list in pairs?

I can’t say for sure but I doubt it: Any other traversal would include more Python code which has to be interpreted. The built-in functions like zip() are written in C which is much faster.

Which would be the right way to ensure that all elements are included?

Check the length of the list and if it’s odd (len(list) & 1 == 1), copy the list and append an item.


回答 5

>>> my_list = [1,2,3,4,5,6,7,8,9,10]
>>> my_pairs = list()
>>> while(my_list):
...     a = my_list.pop(0); b = my_list.pop(0)
...     my_pairs.append((a,b))
... 
>>> print(my_pairs)
[(1, 2), (3, 4), (5, 6), (7, 8), (9, 10)]
>>> my_list = [1,2,3,4,5,6,7,8,9,10]
>>> my_pairs = list()
>>> while(my_list):
...     a = my_list.pop(0); b = my_list.pop(0)
...     my_pairs.append((a,b))
... 
>>> print(my_pairs)
[(1, 2), (3, 4), (5, 6), (7, 8), (9, 10)]

回答 6

只做:

>>> l = [1, 2, 3, 4, 5, 6]
>>> [(x,y) for x,y in zip(l[:-1], l[1:])]
[(1, 2), (2, 3), (3, 4), (4, 5), (5, 6)]

Only do it:

>>> l = [1, 2, 3, 4, 5, 6]
>>> [(x,y) for x,y in zip(l[:-1], l[1:])]
[(1, 2), (2, 3), (3, 4), (4, 5), (5, 6)]

回答 7

这是使用生成器创建对/腿的示例。生成器不受堆栈限制

def pairwise(data):
    zip(data[::2], data[1::2])

例:

print(list(pairwise(range(10))))

输出:

[(0, 1), (2, 3), (4, 5), (6, 7), (8, 9)]

Here is an example of creating pairs/legs by using a generator. Generators are free from stack limits

def pairwise(data):
    zip(data[::2], data[1::2])

Example:

print(list(pairwise(range(10))))

Output:

[(0, 1), (2, 3), (4, 5), (6, 7), (8, 9)]

回答 8

万一有人需要明智的答案算法,这里是:

>>> def getPairs(list):
...     out = []
...     for i in range(len(list)-1):
...         a = list.pop(0)
...         for j in a:
...             out.append([a, j])
...     return b
>>> 
>>> k = [1, 2, 3, 4]
>>> l = getPairs(k)
>>> l
[[1, 2], [1, 3], [1, 4], [2, 3], [2, 4], [3, 4]]

但是请注意,您原来的列表也将被简化为最后一个元素,因为您使用pop了它。

>>> k
[4]

Just in case someone needs the answer algorithm-wise, here it is:

>>> def getPairs(list):
...     out = []
...     for i in range(len(list)-1):
...         a = list.pop(0)
...         for j in a:
...             out.append([a, j])
...     return b
>>> 
>>> k = [1, 2, 3, 4]
>>> l = getPairs(k)
>>> l
[[1, 2], [1, 3], [1, 4], [2, 3], [2, 4], [3, 4]]

But take note that your original list will also be reduced to its last element, because you used pop on it.

>>> k
[4]

Python:根据索引集从列表中选择子集

问题:Python:根据索引集从列表中选择子集

我有几个具有相同数量条目的列表(每个列表都指定一个对象属性):

property_a = [545., 656., 5.4, 33.]
property_b = [ 1.2,  1.3, 2.3, 0.3]
...

并列出具有相同长度的标志

good_objects = [True, False, False, True]

(可以很容易地用等效的索引列表代替:

good_indices = [0, 3]

生成仅包含由条目或索引指示的值的新列表property_aselproperty_bsel… 的最简单方法是什么True

property_asel = [545., 33.]
property_bsel = [ 1.2, 0.3]

I have several lists having all the same number of entries (each specifying an object property):

property_a = [545., 656., 5.4, 33.]
property_b = [ 1.2,  1.3, 2.3, 0.3]
...

and list with flags of the same length

good_objects = [True, False, False, True]

(which could easily be substituted with an equivalent index list:

good_indices = [0, 3]

What is the easiest way to generate new lists property_asel, property_bsel, … which contain only the values indicated either by the True entries or the indices?

property_asel = [545., 33.]
property_bsel = [ 1.2, 0.3]

回答 0

您可以只使用列表推导

property_asel = [val for is_good, val in zip(good_objects, property_a) if is_good]

要么

property_asel = [property_a[i] for i in good_indices]

后者要快一些,因为它good_indices的长度小于的长度property_a,假设good_indices它们是预先计算的,而不是即时生成的。


编辑:第一个选项等效于itertools.compressPython 2.7 / 3.1之后的版本。请参阅@Gary Kerr的答案。

property_asel = list(itertools.compress(property_a, good_objects))

You could just use list comprehension:

property_asel = [val for is_good, val in zip(good_objects, property_a) if is_good]

or

property_asel = [property_a[i] for i in good_indices]

The latter one is faster because there are fewer good_indices than the length of property_a, assuming good_indices are precomputed instead of generated on-the-fly.


Edit: The first option is equivalent to itertools.compress available since Python 2.7/3.1. See @Gary Kerr‘s answer.

property_asel = list(itertools.compress(property_a, good_objects))

回答 1

我看到2个选项。

  1. 使用numpy:

    property_a = numpy.array([545., 656., 5.4, 33.])
    property_b = numpy.array([ 1.2,  1.3, 2.3, 0.3])
    good_objects = [True, False, False, True]
    good_indices = [0, 3]
    property_asel = property_a[good_objects]
    property_bsel = property_b[good_indices]
  2. 使用列表理解并将其压缩:

    property_a = [545., 656., 5.4, 33.]
    property_b = [ 1.2,  1.3, 2.3, 0.3]
    good_objects = [True, False, False, True]
    good_indices = [0, 3]
    property_asel = [x for x, y in zip(property_a, good_objects) if y]
    property_bsel = [property_b[i] for i in good_indices]

I see 2 options.

  1. Using numpy:

    property_a = numpy.array([545., 656., 5.4, 33.])
    property_b = numpy.array([ 1.2,  1.3, 2.3, 0.3])
    good_objects = [True, False, False, True]
    good_indices = [0, 3]
    property_asel = property_a[good_objects]
    property_bsel = property_b[good_indices]
    
  2. Using a list comprehension and zip it:

    property_a = [545., 656., 5.4, 33.]
    property_b = [ 1.2,  1.3, 2.3, 0.3]
    good_objects = [True, False, False, True]
    good_indices = [0, 3]
    property_asel = [x for x, y in zip(property_a, good_objects) if y]
    property_bsel = [property_b[i] for i in good_indices]
    

回答 2

使用内置的功能zip

property_asel = [a for (a, truth) in zip(property_a, good_objects) if truth]

编辑

只看2.7的新功能。itertools模块中现在有一个函数,与上面的代码类似。

http://docs.python.org/library/itertools.html#itertools.compress

itertools.compress('ABCDEF', [1,0,1,0,1,1]) =>
  A, C, E, F

Use the built in function zip

property_asel = [a for (a, truth) in zip(property_a, good_objects) if truth]

EDIT

Just looking at the new features of 2.7. There is now a function in the itertools module which is similar to the above code.

http://docs.python.org/library/itertools.html#itertools.compress

itertools.compress('ABCDEF', [1,0,1,0,1,1]) =>
  A, C, E, F

回答 3

假设您只有项目列表和真实/必需索引列表,那么这应该是最快的:

property_asel = [ property_a[index] for index in good_indices ]

这意味着属性选择将只进行与真实/必需索引一样多的回合。如果您有很多遵循单个标签(真/假)列表规则的属性列表,则可以使用相同的列表理解原则创建索引列表:

good_indices = [ index for index, item in enumerate(good_objects) if item ]

这会遍历good_objects中的每个项目(同时使用枚举记住其索引),并且仅返回该项目为true的索引。


对于没有理解列表的人,这是英文散文版本,其代码以粗体突出显示:

列出每个索引组的索引,索引存在好对象枚举中,如果(其中)该项为True

Assuming you only have the list of items and a list of true/required indices, this should be the fastest:

property_asel = [ property_a[index] for index in good_indices ]

This means the property selection will only do as many rounds as there are true/required indices. If you have a lot of property lists that follow the rules of a single tags (true/false) list you can create an indices list using the same list comprehension principles:

good_indices = [ index for index, item in enumerate(good_objects) if item ]

This iterates through each item in good_objects (while remembering its index with enumerate) and returns only the indices where the item is true.


For anyone not getting the list comprehension, here is an English prose version with the code highlighted in bold:

list the index for every group of index, item that exists in an enumeration of good objects, if (where) the item is True


回答 4

Matlab和Scilab语言为您提出的问题提供了比Python更简单,更优雅的语法,因此,我认为最好的方法是使用Python中的Numpy包来模仿Matlab / Scilab。通过这样做,您的问题的解决方案非常简洁,优雅:

from numpy import *
property_a = array([545., 656., 5.4, 33.])
property_b = array([ 1.2,  1.3, 2.3, 0.3])
good_objects = [True, False, False, True]
good_indices = [0, 3]
property_asel = property_a[good_objects]
property_bsel = property_b[good_indices]

Numpy试图模仿Matlab / Scilab,但这要付出一定的代价:您需要用关键字“ array”声明每个列表,这会使脚本过载(Matlab / Scilab不存在此问题)。请注意,此解决方案仅限于数字数组,在您的示例中就是这种情况。

Matlab and Scilab languages offer a simpler and more elegant syntax than Python for the question you’re asking, so I think the best you can do is to mimic Matlab/Scilab by using the Numpy package in Python. By doing this the solution to your problem is very concise and elegant:

from numpy import *
property_a = array([545., 656., 5.4, 33.])
property_b = array([ 1.2,  1.3, 2.3, 0.3])
good_objects = [True, False, False, True]
good_indices = [0, 3]
property_asel = property_a[good_objects]
property_bsel = property_b[good_indices]

Numpy tries to mimic Matlab/Scilab but it comes at a cost: you need to declare every list with the keyword “array”, something which will overload your script (this problem doesn’t exist with Matlab/Scilab). Note that this solution is restricted to arrays of number, which is the case in your example.


Python:获取列表中第一个字符串的第一个字符?

问题:Python:获取列表中第一个字符串的第一个字符?

如何从Python列表中的第一个字符串中获取第一个字符?

看来我可以使用,mylist[0][1:]但不能给我第一个字符。

>>> mylist = []
>>> mylist.append("asdf")
>>> mylist.append("jkl;")
>>> mylist[0][1:]
'sdf'

How would I get the first character from the first string in a list in Python?

It seems that I could use mylist[0][1:] but that does not give me the first character.

>>> mylist = []
>>> mylist.append("asdf")
>>> mylist.append("jkl;")
>>> mylist[0][1:]
'sdf'

回答 0

你几乎是对的。最简单的方法是

mylist[0][0]   # get the first character from the first item in the list

mylist[0][:1]  # get up to the first character in the first item in the list

也可以。

你想结束的第一个字符(字符零)后,未启动的第一个字符(字符零),这是以后有什么在你的问题的手段的代码。

You almost had it right. The simplest way is

mylist[0][0]   # get the first character from the first item in the list

but

mylist[0][:1]  # get up to the first character in the first item in the list

would also work.

You want to end after the first character (character zero), not start after the first character (character zero), which is what the code in your question means.


回答 1

获取裸python字符串的第一个字符:

>>> mystring = "hello"
>>> print(mystring[0])
h
>>> print(mystring[:1])
h
>>> print(mystring[3])
l
>>> print(mystring[-1])
o
>>> print(mystring[2:3])
l
>>> print(mystring[2:4])
ll

从python列表的第一个位置的字符串中获取第一个字符:

>>> myarray = []
>>> myarray.append("blah")
>>> myarray[0][:1]
'b'
>>> myarray[0][-1]
'h'
>>> myarray[0][1:3]
'la'

许多人在这里绊倒了,因为他们混淆了Python列表对象的运算符和Numpy ndarray对象的运算符:

Numpy操作与python列表操作非常不同。

绕过Python的“列表切片,索引,子集”和Numpy的“掩码,切片,子集,索引,然后是numpy的增强式花式索引”这两个相互冲突的世界。

这两个视频为我清除了一切:

PyCon 2015撰写的“使用NumPy消除循环,快速进行数值计算”:https ://youtu.be/EEUXKG97YRw ? t = 22m22s

Alexandre Chabot LeClerc撰写的“ NumPy初学者| SciPy 2016教程”:https ://youtu.be/gtejJ3RCddE ? t = 1h24m54s

Get the first character of a bare python string:

>>> mystring = "hello"
>>> print(mystring[0])
h
>>> print(mystring[:1])
h
>>> print(mystring[3])
l
>>> print(mystring[-1])
o
>>> print(mystring[2:3])
l
>>> print(mystring[2:4])
ll

Get the first character from a string in the first position of a python list:

>>> myarray = []
>>> myarray.append("blah")
>>> myarray[0][:1]
'b'
>>> myarray[0][-1]
'h'
>>> myarray[0][1:3]
'la'

Many people get tripped up here because they are mixing up operators of Python list objects and operators of Numpy ndarray objects:

Numpy operations are very different than python list operations.

Wrap your head around the two conflicting worlds of Python’s “list slicing, indexing, subsetting” and then Numpy’s “masking, slicing, subsetting, indexing, then numpy’s enhanced fancy indexing”.

These two videos cleared things up for me:

“Losing your Loops, Fast Numerical Computing with NumPy” by PyCon 2015: https://youtu.be/EEUXKG97YRw?t=22m22s

“NumPy Beginner | SciPy 2016 Tutorial” by Alexandre Chabot LeClerc: https://youtu.be/gtejJ3RCddE?t=1h24m54s


回答 2

从0开始在python中建立索引。您编写了[1:]在任何情况下都不会返回第一个字符-这将为您返回其余的字符串(第一个字符除外)。

如果具有以下结构:

mylist = ['base', 'sample', 'test']

并希望为第一个字符串(项目)获取拳头字符:

myList[0][0]
>>> b

如果所有第一个字符:

[x[0] for x in myList]
>>> ['b', 's', 't']    

如果您有文字:

text = 'base sample test'
text.split()[0][0]
>>> b

Indexing in python starting from 0. You wrote [1:] this would not return you a first char in any case – this will return you a rest(except first char) of string.

If you have the following structure:

mylist = ['base', 'sample', 'test']

And want to get fist char for the first one string(item):

myList[0][0]
>>> b

If all first chars:

[x[0] for x in myList]
>>> ['b', 's', 't']    

If you have a text:

text = 'base sample test'
text.split()[0][0]
>>> b

回答 3

尝试mylist[0][0]。这应该返回第一个字符。

Try mylist[0][0]. This should return the first character.


用列表输出而不是元组压缩

问题:用列表输出而不是元组压缩

从两个列表中选择列表的最快,最优雅的方法是什么?

我有

In [1]: a=[1,2,3,4,5,6]

In [2]: b=[7,8,9,10,11,12]

In [3]: zip(a,b)
Out[3]: [(1, 7), (2, 8), (3, 9), (4, 10), (5, 11), (6, 12)]

我想要

In [3]: some_method(a,b)
Out[3]: [[1, 7], [2, 8], [3, 9], [4, 10], [5, 11], [6, 12]]

我当时在考虑使用map而不是zip,但我不知道是否有一些标准库方法作为第一个参数。

我可以为此定义自己的功能,并使用map,我的问题是是否已经实现了某些功能。也是答案。

What is the fastest and most elegant way of doing list of lists from two lists?

I have

In [1]: a=[1,2,3,4,5,6]

In [2]: b=[7,8,9,10,11,12]

In [3]: zip(a,b)
Out[3]: [(1, 7), (2, 8), (3, 9), (4, 10), (5, 11), (6, 12)]

And I’d like to have

In [3]: some_method(a,b)
Out[3]: [[1, 7], [2, 8], [3, 9], [4, 10], [5, 11], [6, 12]]

I was thinking about using map instead of zip, but I don’t know if there is some standard library method to put as a first argument.

I can def my own function for this, and use map, my question is if there is already implemented something. No is also an answer.


回答 0

如果您要压缩2个以上的列表(就此而言,甚至压缩2个),一种可读的方式将是:

[list(a) for a in zip([1,2,3], [4,5,6], [7,8,9])]

这使用列表推导并将列表(元组)中的每个元素转换为列表。

If you are zipping more than 2 lists (or even only 2, for that matter), a readable way would be:

[list(a) for a in zip([1,2,3], [4,5,6], [7,8,9])]

This uses list comprehensions and converts each element in the list (tuples) into lists.


回答 1

您自己几乎已经有了答案。不要使用map代替zip。使用map AND zip

您可以将地图和zip结合使用,以实现优雅,实用的方法:

list(map(list, zip(a, b)))

zip返回一个元组列表。map(list, [...])调用list列表中的每个元组。list(map([...])将地图对象变成可读列表。

You almost had the answer yourself. Don’t use map instead of zip. Use map AND zip.

You can use map along with zip for an elegant, functional approach:

list(map(list, zip(a, b)))

zip returns a list of tuples. map(list, [...]) calls list on each tuple in the list. list(map([...]) turns the map object into a readable list.


回答 2

我喜欢zip函数的优雅,但是在operator模块中使用itemgetter()函数似乎要快得多。我写了一个简单的脚本来测试:

import time
from operator import itemgetter

list1 = list()
list2 = list()
origlist = list()
for i in range (1,5000000):
        t = (i, 2*i)
        origlist.append(t)

print "Using zip"
starttime = time.time()
list1, list2 = map(list, zip(*origlist))
elapsed = time.time()-starttime
print elapsed

print "Using itemgetter"
starttime = time.time()
list1 = map(itemgetter(0),origlist)
list2 = map(itemgetter(1),origlist)
elapsed = time.time()-starttime
print elapsed

我期望zip可以更快,但是itemgetter方法远胜于此:

Using zip
6.1550450325
Using itemgetter
0.768098831177

I love the elegance of the zip function, but using the itemgetter() function in the operator module appears to be much faster. I wrote a simple script to test this:

import time
from operator import itemgetter

list1 = list()
list2 = list()
origlist = list()
for i in range (1,5000000):
        t = (i, 2*i)
        origlist.append(t)

print "Using zip"
starttime = time.time()
list1, list2 = map(list, zip(*origlist))
elapsed = time.time()-starttime
print elapsed

print "Using itemgetter"
starttime = time.time()
list1 = map(itemgetter(0),origlist)
list2 = map(itemgetter(1),origlist)
elapsed = time.time()-starttime
print elapsed

I expected zip to be faster, but the itemgetter method wins by a long shot:

Using zip
6.1550450325
Using itemgetter
0.768098831177

回答 3

我通常不喜欢使用lambda,但是…

>>> a = [1, 2, 3, 4, 5]
>>> b = [6, 7, 8, 9, 10]
>>> c = lambda a, b: [list(c) for c in zip(a, b)]
>>> c(a, b)
[[1, 6], [2, 7], [3, 8], [4, 9], [5, 10]]

如果您需要额外的速度,则地图会稍微快一些:

>>> d = lambda a, b: map(list, zip(a, b))
>>> d(a, b)
[[1, 6], [2, 7], [3, 8], [4, 9], [5, 10]]

但是,映射被认为是非Python的,仅应用于性能调整。

I generally don’t like using lambda, but…

>>> a = [1, 2, 3, 4, 5]
>>> b = [6, 7, 8, 9, 10]
>>> c = lambda a, b: [list(c) for c in zip(a, b)]
>>> c(a, b)
[[1, 6], [2, 7], [3, 8], [4, 9], [5, 10]]

If you need the extra speed, map is slightly faster:

>>> d = lambda a, b: map(list, zip(a, b))
>>> d(a, b)
[[1, 6], [2, 7], [3, 8], [4, 9], [5, 10]]

However, map is considered unpythonic and should only be used for performance tuning.


回答 4

这个怎么样?

>>> def list_(*args): return list(args)

>>> map(list_, range(5), range(9,4,-1))
[[0, 9], [1, 8], [2, 7], [3, 6], [4, 5]]

甚至更好:

>>> def zip_(*args): return map(list_, *args)
>>> zip_(range(5), range(9,4,-1))
[[0, 9], [1, 8], [2, 7], [3, 6], [4, 5]]

How about this?

>>> def list_(*args): return list(args)

>>> map(list_, range(5), range(9,4,-1))
[[0, 9], [1, 8], [2, 7], [3, 6], [4, 5]]

Or even better:

>>> def zip_(*args): return map(list_, *args)
>>> zip_(range(5), range(9,4,-1))
[[0, 9], [1, 8], [2, 7], [3, 6], [4, 5]]

回答 5

使用numpy

优雅的定义可能会令人质疑,但是,如果您要numpy创建数组并将其转换为列表(如果需要…),则可能非常实用,即使使用map函数或列表理解相比效率不高。

import numpy as np 
a = b = range(10)
zipped = zip(a,b)
result = np.array(zipped).tolist()
Out: [[0, 0],
 [1, 1],
 [2, 2],
 [3, 3],
 [4, 4],
 [5, 5],
 [6, 6],
 [7, 7],
 [8, 8],
 [9, 9]]

否则跳过该zip功能,您可以直接使用np.dstack

np.dstack((a,b))[0].tolist()

Using numpy

The definition of elegance can be quite questionable but if you are working with numpy the creation of an array and its conversion to list (if needed…) could be very practical even though not so efficient compared using the map function or the list comprehension.

import numpy as np 
a = b = range(10)
zipped = zip(a,b)
result = np.array(zipped).tolist()
Out: [[0, 0],
 [1, 1],
 [2, 2],
 [3, 3],
 [4, 4],
 [5, 5],
 [6, 6],
 [7, 7],
 [8, 8],
 [9, 9]]

Otherwise skipping the zip function you can use directly np.dstack:

np.dstack((a,b))[0].tolist()

回答 6

我想列表理解将是非常简单的解决方案。

a=[1,2,3,4,5,6]

b=[7,8,9,10,11,12]

x = [[i, j] for i, j in zip(a,b)]

print(x)

output : [[1, 7], [2, 8], [3, 9], [4, 10], [5, 11], [6, 12]]

List comprehension would be very simple solution I guess.

a=[1,2,3,4,5,6]

b=[7,8,9,10,11,12]

x = [[i, j] for i, j in zip(a,b)]

print(x)

output : [[1, 7], [2, 8], [3, 9], [4, 10], [5, 11], [6, 12]]

Python:TypeError:无法散列的类型:“列表”

问题:Python:TypeError:无法散列的类型:“列表”

我正在尝试拍摄一个看起来像这样的文件

AAA x 111
AAB x 111
AAA x 112
AAC x 123
...

并使用字典使输出看起来像这样

{AAA: ['111', '112'], AAB: ['111'], AAC: [123], ...}

这就是我尝试过的

file = open("filename.txt", "r") 
readline = file.readline().rstrip()
while readline!= "":
    list = []
    list = readline.split(" ")
    j = list.index("x")
    k = list[0:j]
    v = list[j + 1:]
    d = {}
    if k not in d == False:
        d[k] = []
    d[k].append(v)
    readline = file.readline().rstrip()

我不断收到TypeError: unhashable type: 'list'。我知道字典中的键不能是列表,但是我试图将我的值变成列表而不是键。我想知道我是否在某个地方犯了一个错误。

I’m trying to take a file that looks like this:

AAA x 111
AAB x 111
AAA x 112
AAC x 123
...

And use a dictionary to so that the output looks like this

{AAA: ['111', '112'], AAB: ['111'], AAC: [123], ...}

This is what I’ve tried

file = open("filename.txt", "r") 
readline = file.readline().rstrip()
while readline!= "":
    list = []
    list = readline.split(" ")
    j = list.index("x")
    k = list[0:j]
    v = list[j + 1:]
    d = {}
    if k not in d == False:
        d[k] = []
    d[k].append(v)
    readline = file.readline().rstrip()

I keep getting a TypeError: unhashable type: 'list'. I know that keys in a dictionary can’t be lists but I’m trying to make my value into a list not the key. I’m wondering if I made a mistake somewhere.


回答 0

如其他答案所示,错误是由于造成的k = list[0:j],您的密钥被转换为列表。您可以尝试做的一件事是重新编写代码以利用该split功能:

# Using with ensures that the file is properly closed when you're done
with open('filename.txt', 'rb') as f:
  d = {}
  # Here we use readlines() to split the file into a list where each element is a line
  for line in f.readlines():
    # Now we split the file on `x`, since the part before the x will be
    # the key and the part after the value
    line = line.split('x')
    # Take the line parts and strip out the spaces, assigning them to the variables
    # Once you get a bit more comfortable, this works as well:
    # key, value = [x.strip() for x in line] 
    key = line[0].strip()
    value = line[1].strip()
    # Now we check if the dictionary contains the key; if so, append the new value,
    # and if not, make a new list that contains the current value
    # (For future reference, this is a great place for a defaultdict :)
    if key in d:
      d[key].append(value)
    else:
      d[key] = [value]

print d
# {'AAA': ['111', '112'], 'AAC': ['123'], 'AAB': ['111']}

请注意,如果您使用的是Python 3.x,则必须稍作调整才能使其正常运行。如果您使用打开文件rb,则需要使用line = line.split(b'x')(确保使用正确的字符串类型分割字节)。您也可以使用with open('filename.txt', 'rU') as f:(甚至with open('filename.txt', 'r') as f:)打开文件,它应该可以正常工作。

As indicated by the other answers, the error is to due to k = list[0:j], where your key is converted to a list. One thing you could try is reworking your code to take advantage of the split function:

# Using with ensures that the file is properly closed when you're done
with open('filename.txt', 'rb') as f:
  d = {}
  # Here we use readlines() to split the file into a list where each element is a line
  for line in f.readlines():
    # Now we split the file on `x`, since the part before the x will be
    # the key and the part after the value
    line = line.split('x')
    # Take the line parts and strip out the spaces, assigning them to the variables
    # Once you get a bit more comfortable, this works as well:
    # key, value = [x.strip() for x in line] 
    key = line[0].strip()
    value = line[1].strip()
    # Now we check if the dictionary contains the key; if so, append the new value,
    # and if not, make a new list that contains the current value
    # (For future reference, this is a great place for a defaultdict :)
    if key in d:
      d[key].append(value)
    else:
      d[key] = [value]

print d
# {'AAA': ['111', '112'], 'AAC': ['123'], 'AAB': ['111']}

Note that if you are using Python 3.x, you’ll have to make a minor adjustment to get it work properly. If you open the file with rb, you’ll need to use line = line.split(b'x') (which makes sure you are splitting the byte with the proper type of string). You can also open the file using with open('filename.txt', 'rU') as f: (or even with open('filename.txt', 'r') as f:) and it should work fine.


回答 1

注意: 此答案未明确回答所提问题。其他答案可以做到。由于问题是特定于场景的,提出的异常是一般的,因此此答案指向一般情况。

哈希值只是整数,用于在字典查找期间快速比较字典关键字。

在内部,hash()方法调用__hash__()对象的方法,该方法默认为任何对象设置。

嵌套列表转换为集合

>>> a = [1,2,3,4,[5,6,7],8,9]
>>> set(a)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: unhashable type: 'list'

发生这种情况是因为列表内的列表是不能散列的列表。可以通过将内部嵌套列表转换为元组来解决,

>>> set([1, 2, 3, 4, (5, 6, 7), 8, 9])
set([1, 2, 3, 4, 8, 9, (5, 6, 7)])

显式哈希嵌套列表

>>> hash([1, 2, 3, [4, 5,], 6, 7])
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: unhashable type: 'list'


>>> hash(tuple([1, 2, 3, [4, 5,], 6, 7]))
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: unhashable type: 'list'

>>> hash(tuple([1, 2, 3, tuple([4, 5,]), 6, 7]))
-7943504827826258506

避免此错误的解决方案是将列表重组为具有嵌套元组而不是列表。

Note: This answer does not explicitly answer the asked question. the other answers do it. Since the question is specific to a scenario and the raised exception is general, This answer points to the general case.

Hash values are just integers which are used to compare dictionary keys during a dictionary lookup quickly.

Internally, hash() method calls __hash__() method of an object which are set by default for any object.

Converting a nested list to a set

>>> a = [1,2,3,4,[5,6,7],8,9]
>>> set(a)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: unhashable type: 'list'

This happens because of the list inside a list which is a list which cannot be hashed. Which can be solved by converting the internal nested lists to a tuple,

>>> set([1, 2, 3, 4, (5, 6, 7), 8, 9])
set([1, 2, 3, 4, 8, 9, (5, 6, 7)])

Explicitly hashing a nested list

>>> hash([1, 2, 3, [4, 5,], 6, 7])
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: unhashable type: 'list'


>>> hash(tuple([1, 2, 3, [4, 5,], 6, 7]))
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: unhashable type: 'list'

>>> hash(tuple([1, 2, 3, tuple([4, 5,]), 6, 7]))
-7943504827826258506

The solution to avoid this error is to restructure the list to have nested tuples instead of lists.


回答 2

您正在尝试使用k(这是一个列表)作为的键d。列表是可变的,不能用作字典键。

另外,由于这一行,您永远不会初始化字典中的列表:

if k not in d == False:

应该是:

if k not in d == True:

实际上应该是:

if k not in d:

You’re trying to use k (which is a list) as a key for d. Lists are mutable and can’t be used as dict keys.

Also, you’re never initializing the lists in the dictionary, because of this line:

if k not in d == False:

Which should be:

if k not in d == True:

Which should actually be:

if k not in d:

回答 3

之所以会出现unhashable type: 'list'异常,是因为k = list[0:j]将其设置k为列表的“切片”,从逻辑上讲,它是另一个(通常较短的)列表。您需要的只是获得列表中的第一项,这样写k = list[0]。对于的调用返回的列表的第三个元素v = list[j + 1:]应该是相同的。v = list[2]readline.split(" ")

我注意到了代码的其他一些可能的问题,我将提及其中的一些问题。一个大的一个是你不希望(重新)初始化dd = {}每一行的循环中读取。另一个是,将变量命名为任何内置类型通常不是一个好主意,因为它会阻止您在需要时访问其中一个变量,并且会使习惯于该变量的其他人感到困惑。指定这些标准项目之一的名称。因此,您应该将变量list变量重命名为其他名称,以避免类似的问题。

这是您的工作版本,其中进行了这些更改,我还简化了if您拥有的语句表达式,该语句表达式可检查键是否已在字典中-甚至有更短的隐式方法来执行此类操作,但使用条件语句声明目前还不错。

d = {}
file = open("filename.txt", "r")
readline = file.readline().rstrip()
while readline:
    lst = readline.split(" ") # Split into sequence like ['AAA', 'x', '111'].
    k = lst[0]  # First item.
    v = lst[2]  # Third item.
    if k not in d:  # New key?
        d[k] = []  # Initialize its associated value to an empty list.
    d[k].append(v)
    readline = file.readline().rstrip()

file.close()  # Done reading file.
print('d: {}'.format(d))

输出:

d: {'AAA': ['111', '112'], 'AAC': ['123'], 'AAB': ['111']}

The reason you’re getting the unhashable type: 'list' exception is because k = list[0:j] sets k to be a “slice” of the list, which is logically another, often shorter, list. What you need is to get just the first item in list, written like so k = list[0]. The same for v = list[j + 1:] which should just be v = list[2] for the third element of the list returned from the call to readline.split(" ").

I noticed several other likely problems with the code, of which I’ll mention a few. A big one is you don’t want to (re)initialize d with d = {} for each line read in the loop. Another is it’s generally not a good idea to name variables the same as any of the built-ins types because it’ll prevent you from being able to access one of them if you need it — and it’s confusing to others who are used to the names designating one of these standard items. For that reason, you ought to rename your variable list variable something different to avoid issues like that.

Here’s a working version of your with these changes in it, I also replaced the if statement expression you used to check to see if the key was already in the dictionary and now make use of a dictionary’s setdefault() method to accomplish the same thing a little more succinctly.

d = {}
with open("nameerror.txt", "r") as file:
    line = file.readline().rstrip()
    while line:
        lst = line.split() # Split into sequence like ['AAA', 'x', '111'].
        k, _, v = lst[:3]  # Get first and third items.
        d.setdefault(k, []).append(v)
        line = file.readline().rstrip()

print('d: {}'.format(d))

Output:

d: {'AAA': ['111', '112'], 'AAC': ['123'], 'AAB': ['111']}

回答 4

之所以TypeError会发生,k是因为是一个列表,因为它是使用另一个带有line的列表中的一个切片创建的k = list[0:j]。这可能类似于k = ' '.join(list[0:j]),因此您需要一个字符串。

除此之外,if正如Jesse的回答所指出的那样,您的陈述不正确,应该读为if k not in dif not k in d(我更喜欢后者)。

您还需要d = {}for循环中清除字典,因为每次迭代都在其中。

请注意,您也不应使用listfile作为变量名,因为您将掩盖内建函数。

这是我重写代码的方法:

d = {}
with open("filename.txt", "r") as input_file:
    for line in input_file:
        fields = line.split()
        j = fields.index("x")
        k = " ".join(fields[:j])
        d.setdefault(k, []).append(" ".join(fields[j+1:]))

dict.setdefault()上面的方法替换了if k not in d代码中的逻辑。

The TypeError is happening because k is a list, since it is created using a slice from another list with the line k = list[0:j]. This should probably be something like k = ' '.join(list[0:j]), so you have a string instead.

In addition to this, your if statement is incorrect as noted by Jesse’s answer, which should read if k not in d or if not k in d (I prefer the latter).

You are also clearing your dictionary on each iteration since you have d = {} inside of your for loop.

Note that you should also not be using list or file as variable names, since you will be masking builtins.

Here is how I would rewrite your code:

d = {}
with open("filename.txt", "r") as input_file:
    for line in input_file:
        fields = line.split()
        j = fields.index("x")
        k = " ".join(fields[:j])
        d.setdefault(k, []).append(" ".join(fields[j+1:]))

The dict.setdefault() method above replaces the if k not in d logic from your code.


回答 5

    python 3.2

    with open("d://test.txt") as f:
              k=(((i.split("\n"))[0].rstrip()).split() for i in f.readlines())
              d={}
              for i,_,v in k:
                      d.setdefault(i,[]).append(v)
    python 3.2

    with open("d://test.txt") as f:
              k=(((i.split("\n"))[0].rstrip()).split() for i in f.readlines())
              d={}
              for i,_,v in k:
                      d.setdefault(i,[]).append(v)

根据字符串长度对Python列表进行排序

问题:根据字符串长度对Python列表进行排序

我想根据字符串长度对字符串列表进行排序。我尝试使用sort,如下所示,但似乎无法给我正确的结果。

xs = ['dddd','a','bb','ccc']
print xs
xs.sort(lambda x,y: len(x) < len(y))
print xs

['dddd', 'a', 'bb', 'ccc']
['dddd', 'a', 'bb', 'ccc']

可能是什么问题?

I want to sort a list of strings based on the string length. I tried to use sort as follows, but it doesn’t seem to give me correct result.

xs = ['dddd','a','bb','ccc']
print xs
xs.sort(lambda x,y: len(x) < len(y))
print xs

['dddd', 'a', 'bb', 'ccc']
['dddd', 'a', 'bb', 'ccc']

What might be wrong?


回答 0

将传递lambda给时sort,您需要返回一个整数,而不是布尔值。因此,您的代码应改为:

xs.sort(lambda x,y: cmp(len(x), len(y)))

请注意,cmp是一个内置函数,cmp(x, y)如果x小于则返回-1 yx等于则返回0 yx大于则返回1 y

当然,您可以改为使用key参数:

xs.sort(key=lambda s: len(s))

这告诉该sort方法根据键函数返回的值进行排序。

编辑:感谢下面的balpha和Ruslan指出您可以len直接将其作为关键参数传递给函数,从而消除了对a的需要lambda

xs.sort(key=len)

正如Ruslan在下面指出的那样,您还可以使用内置的排序函数而不是list.sort方法,该方法创建一个新列表,而不是就地对现有列表进行排序:

print(sorted(xs, key=len))

When you pass a lambda to sort, you need to return an integer, not a boolean. So your code should instead read as follows:

xs.sort(lambda x,y: cmp(len(x), len(y)))

Note that cmp is a builtin function such that cmp(x, y) returns -1 if x is less than y, 0 if x is equal to y, and 1 if x is greater than y.

Of course, you can instead use the key parameter:

xs.sort(key=lambda s: len(s))

This tells the sort method to order based on whatever the key function returns.

EDIT: Thanks to balpha and Ruslan below for pointing out that you can just pass len directly as the key parameter to the function, thus eliminating the need for a lambda:

xs.sort(key=len)

And as Ruslan points out below, you can also use the built-in sorted function rather than the list.sort method, which creates a new list rather than sorting the existing one in-place:

print(sorted(xs, key=len))

回答 1

与Eli的答案相同-只是使用较短的表格,因为您可以lambda在此处跳过一部分。

创建新列表:

>>> xs = ['dddd','a','bb','ccc']
>>> sorted(xs, key=len)
['a', 'bb', 'ccc', 'dddd']

就地排序:

>>> xs.sort(key=len)
>>> xs
['a', 'bb', 'ccc', 'dddd']

The same as in Eli’s answer – just using a shorter form, because you can skip a lambda part here.

Creating new list:

>>> xs = ['dddd','a','bb','ccc']
>>> sorted(xs, key=len)
['a', 'bb', 'ccc', 'dddd']

In-place sorting:

>>> xs.sort(key=len)
>>> xs
['a', 'bb', 'ccc', 'dddd']

回答 2

我想添加排序时pythonic键函数的工作方式:

装饰-排序-非装饰设计模式:

当使用所谓的decorate-sort-undecorate设计模式实现排序时,Python对关键功能的支持。

它分3个步骤进行:

  1. 列表中的每个元素都会临时替换为“修饰的”版本,其中包含应用于该元素的键函数的结果。

  2. 该列表是根据键的自然顺序排序的。

  3. 装饰元素将替换为原始元素。

用于在进行比较之前在每个列表元素上指定要调用的函数的关键参数。docs

I Would like to add how the pythonic key function works while sorting :

Decorate-Sort-Undecorate Design Pattern :

Python’s support for a key function when sorting is implemented using what is known as the decorate-sort-undecorate design pattern.

It proceeds in 3 steps:

  1. Each element of the list is temporarily replaced with a “decorated” version that includes the result of the key function applied to the element.

  2. The list is sorted based upon the natural order of the keys.

  3. The decorated elements are replaced by the original elements.

Key parameter to specify a function to be called on each list element prior to making comparisons. docs


回答 3

最简单的方法是:

list.sort(key = lambda x:len(x))

The easiest way to do this is:

list.sort(key = lambda x:len(x))


回答 4

编写一个功能Lensort以根据长度对字符串列表进行排序。

def lensort(a):
    n = len(a)
    for i in range(n):
        for j in range(i+1,n):
            if len(a[i]) > len(a[j]):
                temp = a[i]
                a[i] = a[j]
                a[j] = temp
    return a
print lensort(["hello","bye","good"])

Write a function lensort to sort a list of strings based on length.

def lensort(a):
    n = len(a)
    for i in range(n):
        for j in range(i+1,n):
            if len(a[i]) > len(a[j]):
                temp = a[i]
                a[i] = a[j]
                a[j] = temp
    return a
print lensort(["hello","bye","good"])

回答 5

def lensort(list_1):
    list_2=[];list_3=[]
for i in list_1:
    list_2.append([i,len(i)])
list_2.sort(key = lambda x : x[1])
for i in list_2:
    list_3.append(i[0])
return list_3

这对我有用!

def lensort(list_1):
    list_2=[];list_3=[]
for i in list_1:
    list_2.append([i,len(i)])
list_2.sort(key = lambda x : x[1])
for i in list_2:
    list_3.append(i[0])
return list_3

This works for me!


回答 6

我可以使用以下两种方法来实现

def lensort(x):
    list1 = []
    for i in x:
        list1.append([len(i),i])
    return sorted(list1)

lista = ['a', 'bb', 'ccc', 'dddd']
a=lensort(lista)
print([l[1] for l in a])

在使用Lambda的一个Liner中,如下所示,上面已经给出了答案。

 lista = ['a', 'bb', 'ccc', 'dddd']
 lista.sort(key = lambda x:len(x))
 print(lista)

I can do it using below two methods, using function

def lensort(x):
    list1 = []
    for i in x:
        list1.append([len(i),i])
    return sorted(list1)

lista = ['a', 'bb', 'ccc', 'dddd']
a=lensort(lista)
print([l[1] for l in a])

In one Liner using Lambda, as below, a already answered above.

 lista = ['a', 'bb', 'ccc', 'dddd']
 lista.sort(key = lambda x:len(x))
 print(lista)

检查条件是否满足列表中任何元素的Python方法

问题:检查条件是否满足列表中任何元素的Python方法

我在Python中有一个列表,我想检查是否有任何负数。Specman具有has()用于列表的方法,该方法可以:

x: list of uint;
if (x.has(it < 0)) {
    // do something
};

itSpecman关键字又在哪里映射到列表的每个元素。

我觉得这很优雅。我浏览了Python文档,找不到类似的东西。我能想到的最好的是:

if (True in [t < 0 for t in x]):
    # do something

我觉得这很不雅致。有没有更好的方法在Python中执行此操作?

I have a list in Python, and I want to check if any elements are negative. Specman has the has() method for lists which does:

x: list of uint;
if (x.has(it < 0)) {
    // do something
};

Where it is a Specman keyword mapped to each element of the list in turn.

I find this rather elegant. I looked through the Python documentation and couldn’t find anything similar. The best I could come up with was:

if (True in [t < 0 for t in x]):
    # do something

I find this rather inelegant. Is there a better way to do this in Python?


回答 0

any()

if any(t < 0 for t in x):
    # do something

另外,如果要使用“ True in …”,请将其设为生成器表达式,这样就不会占用O(n)内存:

if True in (t < 0 for t in x):

any():

if any(t < 0 for t in x):
    # do something

Also, if you’re going to use “True in …”, make it a generator expression so it doesn’t take O(n) memory:

if True in (t < 0 for t in x):

回答 1

使用any()

if any(t < 0 for t in x):
    # do something

Use any().

if any(t < 0 for t in x):
    # do something

回答 2

正是出于这个目的,Python内置了any()函数。

Python has a built in any() function for exactly this purpose.


一些内置在python中填充列表的功能

问题:一些内置在python中填充列表的功能

我有一个尺寸小于N的清单我想用一个值将其填充到大小N。

当然,我可以使用类似以下的内容,但是我觉得应该缺少一些内容:

>>> N = 5
>>> a = [1]
>>> map(lambda x, y: y if x is None else x, a, ['']*N)
[1, '', '', '', '']

I have a list of size < N and I want to pad it up to the size N with a value.

Certainly, I can use something like the following, but I feel that there should be something I missed:

>>> N = 5
>>> a = [1]
>>> map(lambda x, y: y if x is None else x, a, ['']*N)
[1, '', '', '', '']

回答 0

a += [''] * (N - len(a))

或者如果您不想更改a位置

new_a = a + [''] * (N - len(a))

您可以随时创建list的子类并随便调用该方法

class MyList(list):
    def ljust(self, n, fillvalue=''):
        return self + [fillvalue] * (n - len(self))

a = MyList(['1'])
b = a.ljust(5, '')
a += [''] * (N - len(a))

or if you don’t want to change a in place

new_a = a + [''] * (N - len(a))

you can always create a subclass of list and call the method whatever you please

class MyList(list):
    def ljust(self, n, fillvalue=''):
        return self + [fillvalue] * (n - len(self))

a = MyList(['1'])
b = a.ljust(5, '')

回答 1

我认为这种方法更具视觉效果和Python风格。

a = (a + N * [''])[:N]

I think this approach is more visual and pythonic.

a = (a + N * [''])[:N]

回答 2

没有内置功能。但是您可以为您的任务(或任何:p)组成内置函数。

(从itertool padnonetake配方修改)

from itertools import chain, repeat, islice

def pad_infinite(iterable, padding=None):
   return chain(iterable, repeat(padding))

def pad(iterable, size, padding=None):
   return islice(pad_infinite(iterable, padding), size)

用法:

>>> list(pad([1,2,3], 7, ''))
[1, 2, 3, '', '', '', '']

There is no built-in function for this. But you could compose the built-ins for your task (or anything :p).

(Modified from itertool’s padnone and take recipes)

from itertools import chain, repeat, islice

def pad_infinite(iterable, padding=None):
   return chain(iterable, repeat(padding))

def pad(iterable, size, padding=None):
   return islice(pad_infinite(iterable, padding), size)

Usage:

>>> list(pad([1,2,3], 7, ''))
[1, 2, 3, '', '', '', '']

回答 3

gnibbler的答案更好,但是如果需要内置的,可以使用itertools.izip_longestzip_longest在Py3k中):

itertools.izip_longest( xrange( N ), list )

这将返回( i, list[ i ] )填充为None 的元组列表。如果您需要摆脱柜台问题,请执行以下操作:

map( itertools.itemgetter( 1 ), itertools.izip_longest( xrange( N ), list ) )

gnibbler’s answer is nicer, but if you need a builtin, you could use itertools.izip_longest (zip_longest in Py3k):

itertools.izip_longest( xrange( N ), list )

which will return a list of tuples ( i, list[ i ] ) filled-in to None. If you need to get rid of the counter, do something like:

map( itertools.itemgetter( 1 ), itertools.izip_longest( xrange( N ), list ) )

回答 4

您也可以使用没有任何内置插件的简单生成器。但是我不会填充列表,而是让应用程序逻辑处理一个空列表。

无论如何,没有内置插件的迭代器

def pad(iterable, padding='.', length=7):
    '''
    >>> iterable = [1,2,3]
    >>> list(pad(iterable))
    [1, 2, 3, '.', '.', '.', '.']
    '''
    for count, i in enumerate(iterable):
        yield i
    while count < length - 1:
        count += 1
        yield padding

if __name__ == '__main__':
    import doctest
    doctest.testmod()

You could also use a simple generator without any build ins. But I would not pad the list, but let the application logic deal with an empty list.

Anyhow, iterator without buildins

def pad(iterable, padding='.', length=7):
    '''
    >>> iterable = [1,2,3]
    >>> list(pad(iterable))
    [1, 2, 3, '.', '.', '.', '.']
    '''
    for count, i in enumerate(iterable):
        yield i
    while count < length - 1:
        count += 1
        yield padding

if __name__ == '__main__':
    import doctest
    doctest.testmod()

回答 5

如果要用None而不是”填充,则map()可以完成此工作:

>>> map(None,[1,2,3],xrange(7))

[(1, 0), (2, 1), (3, 2), (None, 3), (None, 4), (None, 5), (None, 6)]

>>> zip(*map(None,[1,2,3],xrange(7)))[0]

(1, 2, 3, None, None, None, None)

If you want to pad with None instead of ”, map() does the job:

>>> map(None,[1,2,3],xrange(7))

[(1, 0), (2, 1), (3, 2), (None, 3), (None, 4), (None, 5), (None, 6)]

>>> zip(*map(None,[1,2,3],xrange(7)))[0]

(1, 2, 3, None, None, None, None)

回答 6

more-itertools是一个包含padded针对此类问题的专用工具的库:

import more_itertools as mit

list(mit.padded(a, "", N))
# [1, '', '', '', '']

另外,more_itertools还可以实现Python itertools配方padnonetake如@kennytm所述,包括和,因此不必重新实现它们:

list(mit.take(N, mit.padnone(a)))
# [1, None, None, None, None]

如果要替换默认的None填充,请使用列表理解:

["" if i is None else i for i in mit.take(N, mit.padnone(a))]
# [1, '', '', '', '']

more-itertools is a library that includes a special padded tool for this kind of problem:

import more_itertools as mit

list(mit.padded(a, "", N))
# [1, '', '', '', '']

Alternatively, more_itertools also implements Python itertools recipes including padnone and take as mentioned by @kennytm, so they don’t have to be reimplemented:

list(mit.take(N, mit.padnone(a)))
# [1, None, None, None, None]

If you wish to replace the default None padding, use a list comprehension:

["" if i is None else i for i in mit.take(N, mit.padnone(a))]
# [1, '', '', '', '']

回答 7

离开kennytm:

def pad(l, size, padding):
    return l + [padding] * abs((len(l)-size))

>>> l = [1,2,3]
>>> pad(l, 7, 0)
[1, 2, 3, 0, 0, 0, 0]

To go off of kennytm:

def pad(l, size, padding):
    return l + [padding] * abs((len(l)-size))

>>> l = [1,2,3]
>>> pad(l, 7, 0)
[1, 2, 3, 0, 0, 0, 0]

回答 8

您可以使用* 可迭代的拆包运算符

N = 5
a = [1]

pad_value = ''
pad_size = N - len(a)

final_list = [*a, *[pad_value] * pad_size]
print(final_list)

输出:

[1, '', '', '', '']

you can use * iterable unpacking operator:

N = 5
a = [1]

pad_value = ''
pad_size = N - len(a)

final_list = [*a, *[pad_value] * pad_size]
print(final_list)

output:

[1, '', '', '', '']

回答 9

extra_length = desired_length - len(l)
l.extend(value for _ in range(extra_length))

与依赖于创建和追加list的任何解决方案不同,这避免了任何额外的分配[value] * extra_length。“ extend”方法首先调用__length_hint__迭代器,并l在从迭代器填充之前将分配扩展了那么多。

extra_length = desired_length - len(l)
l.extend(value for _ in range(extra_length))

This avoids any extra allocation, unlike any solution that depends on creating and appending the list [value] * extra_length. The “extend” method first calls __length_hint__ on the iterator, and extends the allocation for l by that much before filling it in from the iterator.