I have two lists that i need to combine where the second list has any duplicates of the first list ignored. .. A bit hard to explain, so let me show an example of what the code looks like, and what i want as a result.
first_list = [1, 2, 2, 5]
second_list = [2, 5, 7, 9]
# The result of combining the two lists should result in this list:
resulting_list = [1, 2, 2, 5, 7, 9]
You’ll notice that the result has the first list, including its two “2” values, but the fact that second_list also has an additional 2 and 5 value is not added to the first list.
Normally for something like this i would use sets, but a set on first_list would purge the duplicate values it already has. So i’m simply wondering what the best/fastest way to achieve this desired combination.
You need to append to the first list those elements of the second list that aren’t in the first – sets are the easiest way of determining which elements they are, like this:
first_list =[1,2,2,5]
second_list =[2,5,7,9]
fs = set(first_list)
resulting_list = first_list +[x for x in second_list if x notin fs]assert(resulting_list ==[1,2,2,5,7,9])
def union(a,b):
for e in b:
if e not in a:
a.append(e)
The union function merges the second list into first, with out duplicating an element of a, if it’s already in a. Similar to set union operator. This function does not change b. If a=[1,2,3] b=[2,3,4]. After union(a,b) makes a=[1,2,3,4] and b=[2,3,4]
first_list =[1,2,2,5]
second_list =[2,5,7,9]
newList=[]for i in first_list:
newList.append(i)for z in second_list:if z notin newList:
newList.append(z)
newList.sort()print newList
first_list = [1, 2, 2, 5]
second_list = [2, 5, 7, 9]
newList=[]
for i in first_list:
newList.append(i)
for z in second_list:
if z not in newList:
newList.append(z)
newList.sort()
print newList
You can get the same behavior on Python 2.x using from __future__ import print_function, as noted by mgilson in comments.
With the print statement on Python 2.x you will need iteration of some kind, regarding your question about print(p) for p in myList not working, you can just use the following which does the same thing and is still one line:
for p in myList: print p
For a solution that uses '\n'.join(), I prefer list comprehensions and generators over map() so I would probably use the following:
print '\n'.join(str(p) for p in myList)
回答 1
我经常用这个 :
#!/usr/bin/python
l =[1,2,3,7]print"".join([str(x)for x in l])
If you overload the function __str__() for your Person class, you can omit the part with map(str, …). Another way for this is creating a function, just like you wrote:
def write_list(lst):
for item in lst:
print str(item)
...
write_list(MyList)
There is in Python 3.* the argument sep for the print() function. Take a look at documentation.
回答 4
扩展@lucasg的答案(受其收到的评论启发):
要获得格式化的列表输出,可以按照以下步骤进行操作:
l =[1,2,5]print", ".join('%02d'%x for x in l)01,02,05
Expanding @lucasg’s answer (inspired by the comment it received):
To get a formatted list output, you can do something along these lines:
l = [1,2,5]
print ", ".join('%02d'%x for x in l)
01, 02, 05
Now the ", " provides the separator (only between items, not at the end) and the formatting string '02d'combined with %x gives a formatted string for each item x – in this case, formatted as an integer with two digits, left-filled with zeros.
回答 5
要显示每个内容,我使用:
mylist =['foo','bar']
indexval =0for i in range(len(mylist)):print(mylist[indexval])
indexval +=1
在函数中使用的示例:
def showAll(listname, startat):
indexval = startat
try:for i in range(len(mylist)):print(mylist[indexval])
indexval = indexval +1exceptIndexError:print('That index value you gave is out of range.')
mylist = ['foo', 'bar']
indexval = 0
for i in range(len(mylist)):
print(mylist[indexval])
indexval += 1
Example of using in a function:
def showAll(listname, startat):
indexval = startat
try:
for i in range(len(mylist)):
print(mylist[indexval])
indexval = indexval + 1
except IndexError:
print('That index value you gave is out of range.')
Hope I helped.
回答 6
我认为如果您只想查看列表中的内容,这是最方便的:
myList =['foo','bar']print('myList is %s'% str(myList))
x =0
up =0
passwordText =""
password =[]
userInput = int(input("Enter how many characters you want your password to be: "))print("\n\n\n")# spacingwhile x <=(userInput -1):#loops as many times as the user inputs above
password.extend([choice(groups.characters)])#adds random character from groups file that has all lower/uppercase letters and all numbers
x = x+1#adds 1 to x w/o using x ++1 as I get many errors w/ that
passwordText = passwordText + password[up]
up = up+1# same as x increaseprint(passwordText)
I recently made a password generator and although I’m VERY NEW to python, I whipped this up as a way to display all items in a list (with small edits to fit your needs…
x = 0
up = 0
passwordText = ""
password = []
userInput = int(input("Enter how many characters you want your password to be: "))
print("\n\n\n") # spacing
while x <= (userInput - 1): #loops as many times as the user inputs above
password.extend([choice(groups.characters)]) #adds random character from groups file that has all lower/uppercase letters and all numbers
x = x+1 #adds 1 to x w/o using x ++1 as I get many errors w/ that
passwordText = passwordText + password[up]
up = up+1 # same as x increase
print(passwordText)
Like I said, IM VERY NEW to Python and I’m sure this is way to clunky for a expert, but I’m just here for another example
回答 9
假设您可以很好地打印列表[1,2,3],那么Python3中的一种简单方法是:
mylist=[1,2,3,'lorem','ipsum','dolor','sit','amet']print(f"There are {len(mylist):d} items in this lorem list: {str(mylist):s}")
Operators like <= in Python are generally not overriden to mean something significantly different than “less than or equal to”. It’s unusual for the standard library does this–it smells like legacy API to me.
Use the equivalent and more clearly-named method, set.issubset. Note that you don’t need to convert the argument to a set; it’ll do that for you if needed.
I would probably use set in the following manner :
set(l).issuperset(set(['a','b']))
or the other way round :
set(['a','b']).issubset(set(l))
I find it a bit more readable, but it may be over-kill. Sets are particularly useful to compute union/intersection/differences between collections, but it may not be the best option in this situation …
I like these two because they seem the most logical, the latter being shorter and probably fastest (shown here using set literal syntax which has been backported to Python 2.7):
all(x in {'a', 'b', 'c'} for x in ['a', 'b'])
# or
{'a', 'b'}.issubset({'a', 'b', 'c'})
回答 3
如果您的列表包含这样的重复项,该怎么办:
v1 =['s','h','e','e','p']
v2 =['s','s','h']
集不包含重复项。因此,以下行返回True。
set(v2).issubset(v1)
要计算重复项,可以使用以下代码:
v1 = sorted(v1)
v2 = sorted(v2)def is_subseq(v2, v1):"""Check whether v2 is a subsequence of v1."""
it = iter(v1)return all(c in it for c in v2)
Sets do not contain duplicates. So, the following line returns True.
set(v2).issubset(v1)
To count for duplicates, you can use the code:
v1 = sorted(v1)
v2 = sorted(v2)
def is_subseq(v2, v1):
"""Check whether v2 is a subsequence of v1."""
it = iter(v1)
return all(c in it for c in v2)
So, the following line returns False.
is_subseq(v2, v1)
回答 4
这就是我在网上搜索的内容,但不幸的是,我在python解释器上进行实验时发现不是在线的。
>>> case ="caseCamel">>> label ="Case Camel">>> list =["apple","banana"]>>>>>>(case or label)in list
False>>> list =["apple","caseCamel"]>>>(case or label)in list
True>>>(case and label)in list
False>>> list =["case","caseCamel","Case Camel"]>>>(case and label)in list
True>>>
如果您有一个完整的变量列表 sublist variable
>>>>>> list =["case","caseCamel","Case Camel"]>>> label ="Case Camel">>> case ="caseCamel">>>>>> sublist =["unique banana","very unique banana"]>>>>>># example for if any (at least one) item contained in superset (or statement)...>>> next((Truefor item in sublist if next((Truefor x in list if x == item),False)),False)False>>>>>> sublist[0]= label
>>>>>> next((Truefor item in sublist if next((Truefor x in list if x == item),False)),False)True>>>>>># example for whether a subset (all items) contained in superset (and statement)...>>># a bit of demorgan's law...>>> next((Falsefor item in sublist if item notin list),True)False>>>>>> sublist[1]= case
>>>>>> next((Falsefor item in sublist if item notin list),True)True>>>>>> next((Truefor item in sublist if next((Truefor x in list if x == item),False)),False)True>>>>>>
This was what I was searching online but unfortunately found not online but while experimenting on python interpreter.
>>> case = "caseCamel"
>>> label = "Case Camel"
>>> list = ["apple", "banana"]
>>>
>>> (case or label) in list
False
>>> list = ["apple", "caseCamel"]
>>> (case or label) in list
True
>>> (case and label) in list
False
>>> list = ["case", "caseCamel", "Case Camel"]
>>> (case and label) in list
True
>>>
and if you have a looong list of variables held in a sublist variable
>>>
>>> list = ["case", "caseCamel", "Case Camel"]
>>> label = "Case Camel"
>>> case = "caseCamel"
>>>
>>> sublist = ["unique banana", "very unique banana"]
>>>
>>> # example for if any (at least one) item contained in superset (or statement)
...
>>> next((True for item in sublist if next((True for x in list if x == item), False)), False)
False
>>>
>>> sublist[0] = label
>>>
>>> next((True for item in sublist if next((True for x in list if x == item), False)), False)
True
>>>
>>> # example for whether a subset (all items) contained in superset (and statement)
...
>>> # a bit of demorgan's law
...
>>> next((False for item in sublist if item not in list), True)
False
>>>
>>> sublist[1] = case
>>>
>>> next((False for item in sublist if item not in list), True)
True
>>>
>>> next((True for item in sublist if next((True for x in list if x == item), False)), False)
True
>>>
>>>
>>> a ={'key':'value'}>>> b ={'key':'value','extra_key':'extra_value'}>>> all(item in a.items()for item in b.items())True>>> all(item in b.items()for item in a.items())False
Not OP’s case, but – for anyone who wants to assert intersection in dicts and ended up here due to poor googling (e.g. me) – you need to work with dict.items:
>>> a = {'key': 'value'}
>>> b = {'key': 'value', 'extra_key': 'extra_value'}
>>> all(item in a.items() for item in b.items())
True
>>> all(item in b.items() for item in a.items())
False
That’s because dict.items returns tuples of key/value pairs, and much like any object in Python, they’re interchangeably comparable
from itertools import tee
# python2 only:#from itertools import izip as zipdef differences(seq):
iterable, copied = tee(seq)
next(copied)for x, y in zip(iterable, copied):yield y - x
from itertools import islice
def differences(seq):
nexts = islice(seq,1,None)for x, y in zip(seq, nexts):yield y - x
您也可以避免使用itertools模块:
def differences(seq):
iterable = iter(seq)
prev = next(iterable)for element in iterable:yield element - prev
prev = element
如果您不需要存储所有结果并支持无限的可迭代对象,那么所有这些解决方案都可以在恒定的空间中工作。
以下是解决方案的一些微观基准:
In[12]: L = range(10**6)In[13]:from collections import deque
In[15]:%timeit deque(differences_tee(L), maxlen=0)10 loops, best of 3:122 ms per loop
In[16]:%timeit deque(differences_islice(L), maxlen=0)10 loops, best of 3:127 ms per loop
In[17]:%timeit deque(differences_no_it(L), maxlen=0)10 loops, best of 3:89.9 ms per loop
以及其他建议的解决方案:
In[18]:%timeit [x[1]- x[0]for x in zip(L[1:], L)]10 loops, best of 3:163 ms per loop
In[19]:%timeit [L[i+1]-L[i]for i in range(len(L)-1)]1 loops, best of 3:395 ms per loop
In[20]:import numpy as np
In[21]:%timeit np.diff(L)1 loops, best of 3:479 ms per loop
In[35]:%%timeit
...: res =[]...:for i in range(len(L)-1):...: res.append(L[i+1]- L[i])...:1 loops, best of 3:234 ms per loop
You can use itertools.tee and zip to efficiently build the result:
from itertools import tee
# python2 only:
#from itertools import izip as zip
def differences(seq):
iterable, copied = tee(seq)
next(copied)
for x, y in zip(iterable, copied):
yield y - x
from itertools import islice
def differences(seq):
nexts = islice(seq, 1, None)
for x, y in zip(seq, nexts):
yield y - x
You can also avoid using the itertools module:
def differences(seq):
iterable = iter(seq)
prev = next(iterable)
for element in iterable:
yield element - prev
prev = element
All these solution work in constant space if you don’t need to store all the results and support infinite iterables.
Here are some micro-benchmarks of the solutions:
In [12]: L = range(10**6)
In [13]: from collections import deque
In [15]: %timeit deque(differences_tee(L), maxlen=0)
10 loops, best of 3: 122 ms per loop
In [16]: %timeit deque(differences_islice(L), maxlen=0)
10 loops, best of 3: 127 ms per loop
In [17]: %timeit deque(differences_no_it(L), maxlen=0)
10 loops, best of 3: 89.9 ms per loop
And the other proposed solutions:
In [18]: %timeit [x[1] - x[0] for x in zip(L[1:], L)]
10 loops, best of 3: 163 ms per loop
In [19]: %timeit [L[i+1]-L[i] for i in range(len(L)-1)]
1 loops, best of 3: 395 ms per loop
In [20]: import numpy as np
In [21]: %timeit np.diff(L)
1 loops, best of 3: 479 ms per loop
In [35]: %%timeit
...: res = []
...: for i in range(len(L) - 1):
...: res.append(L[i+1] - L[i])
...:
1 loops, best of 3: 234 ms per loop
Note that:
zip(L[1:], L) is equivalent to zip(L[1:], L[:-1]) since zip already terminates on the shortest input, however it avoids a whole copy of L.
Accessing the single elements by index is very slow because every index access is a method call in python
numpy.diff is slow because it has to first convert the list to a ndarray. Obviously if you start with an ndarray it will be much faster:
In [22]: arr = np.array(L)
In [23]: %timeit np.diff(arr)
100 loops, best of 3: 3.02 ms per loop
回答 4
使用:=Python 3.8+中可用的walrus运算符:
>>> t =[1,3,6]>>> prev = t[0];[-prev +(prev := x)for x in t[1:]][2,3]
But if you want v to have the same length as t then
v = np.diff([t[0]] + t) # for python 3.x
or
v = np.diff(t + [t[-1]])
FYI: this will only work for lists.
for numpy arrays
v = np.diff(np.append(t[0], t))
回答 6
功能方法:
>>>import operator
>>> a =[1,3,5,7,11,13,17,21]>>> map(operator.sub, a[1:], a[:-1])[2,2,2,4,2,4,4]
使用生成器:
>>>import operator, itertools
>>> g1,g2 = itertools.tee((x*x for x in xrange(5)),2)>>> list(itertools.imap(operator.sub, itertools.islice(g1,1,None), g2))[1,3,5,7]
使用索引:
>>>[a[i+1]-a[i]for i in xrange(len(a)-1)][2,2,2,4,2,4,4]
Sometimes with numerical integration you will want to difference a list with periodic boundary conditions (so the first element calculates the difference to the last. In this case the numpy.roll function is helpful:
v-np.roll(v,1)
Solutions with zero prepended
Another numpy solution (just for completeness) is to use
numpy.ediff1d(v)
This works as numpy.diff, but only on a vector (it flattens the input array). It offers the ability to prepend or append numbers to the resulting vector. This is useful when handling accumulated fields that is often the case fluxes in meteorological variables (e.g. rain, latent heat etc), as you want a resulting list of the same length as the input variable, with the first entry untouched.
Then you would write
np.ediff1d(v,to_begin=v[0])
Of course, you can also do this with the np.diff command, in this case though you need to prepend zero to the series with the prepend keyword:
np.diff(v,prepend=0.0)
All the above solutions return a vector that is the same length as the input.
回答 9
我的方式
>>>v =[1,2,3,4,5]>>>[v[i]- v[i-1]for i, value in enumerate(v[1:],1)][1,1,1,1]
$ echo -e "a b c\naaaaaaaaaa b c\na bbbbbbbbbb c"
a b c
aaaaaaaaaa b c
a bbbbbbbbbb c
$ echo -e "a b c\naaaaaaaaaa b c\na bbbbbbbbbb c"| column -t
a b c
aaaaaaaaaa b c
a bbbbbbbbbb c
Using plain tabs wont do the trick here because I don’t know the longest data in each row.
This is the same behavior as ‘column -t’ in Linux..
$ echo -e "a b c\naaaaaaaaaa b c\na bbbbbbbbbb c"
a b c
aaaaaaaaaa b c
a bbbbbbbbbb c
$ echo -e "a b c\naaaaaaaaaa b c\na bbbbbbbbbb c" | column -t
a b c
aaaaaaaaaa b c
a bbbbbbbbbb c
I have looked around for various python libraries to do this but can’t find anything useful.
回答 0
data =[['a','b','c'],['aaaaaaaaaa','b','c'],['a','bbbbbbbbbb','c']]
col_width = max(len(word)for row in data for word in row)+2# paddingfor row in data:print"".join(word.ljust(col_width)for word in row)
a b c
aaaaaaaaaa b c
a bbbbbbbbbb c
data = [['a', 'b', 'c'], ['aaaaaaaaaa', 'b', 'c'], ['a', 'bbbbbbbbbb', 'c']]
col_width = max(len(word) for row in data for word in row) + 2 # padding
for row in data:
print "".join(word.ljust(col_width) for word in row)
a b c
aaaaaaaaaa b c
a bbbbbbbbbb c
What this does is calculate the longest data entry to determine the column width, then use .ljust() to add the necessary padding when printing out each column.
>>> widths =[max(map(len, col))for col in zip(*rows)]>>>for row in rows:...print" ".join((val.ljust(width)for val, width in zip(row, widths)))...
a b c d
aaaaaaaaaa b c d
a bbbbbbbbbb c d
I came here with the same requirements but @lvc and @Preet’s answers seems more inline with what column -t produces in that columns have different widths:
>>> widths = [max(map(len, col)) for col in zip(*rows)]
>>> for row in rows:
... print " ".join((val.ljust(width) for val, width in zip(row, widths)))
...
a b c d
aaaaaaaaaa b c d
a bbbbbbbbbb c d
from columnar import columnar
headers =['name','id','host','notes']
data =[['busybox','c3c37d5d-38d2-409f-8d02-600fd9d51239','linuxnode-1-292735','Test server.'],['alpine-python','6bb77855-0fda-45a9-b553-e19e1a795f1e','linuxnode-2-249253','The one that runs python.'],['redis','afb648ba-ac97-4fb2-8953-9a5b5f39663e','linuxnode-3-3416918','For queues and stuff.'],['app-server','b866cd0f-bf80-40c7-84e3-c40891ec68f9','linuxnode-4-295918','A popular destination.'],['nginx','76fea0f0-aa53-4911-b7e4-fae28c2e469b','linuxnode-5-292735','Traffic Cop'],]
table = columnar(data, headers, no_borders=True)print(table)
formatting the columns using our knowledge of max width from the first pass using str.ljust() and str.rjust()
回答 5
像这样转换列是zip的工作:
>>> a =[['a','b','c'],['aaaaaaaaaa','b','c'],['a','bbbbbbbbbb','c']]>>> list(zip(*a))[('a','aaaaaaaaaa','a'),('b','b','bbbbbbbbbb'),('c','c','c')]
要查找每列所需的长度,可以使用max:
>>> trans_a = zip(*a)>>>[max(len(c)for c in b)for b in trans_a][10,10,1]
您可以在适当的填充下使用它来构造要传递给的字符串print:
>>> col_lenghts =[max(len(c)for c in b)for b in trans_a]>>> padding =' '# You might want more>>> padding.join(s.ljust(l)for s,l in zip(a[0], col_lenghts))'a b c'
To find the required length of each column, you can use max:
>>> trans_a = zip(*a)
>>> [max(len(c) for c in b) for b in trans_a]
[10, 10, 1]
Which you can use, with suitable padding, to construct strings to pass to print:
>>> col_lenghts = [max(len(c) for c in b) for b in trans_a]
>>> padding = ' ' # You might want more
>>> padding.join(s.ljust(l) for s,l in zip(a[0], col_lenghts))
'a b c'
'''
From http://code.activestate.com/recipes/267662-table-indentation/
PSF License
'''import cStringIO,operator
def indent(rows, hasHeader=False, headerChar='-', delim=' | ', justify='left',
separateRows=False, prefix='', postfix='', wrapfunc=lambda x:x):"""Indents a table by column.
- rows: A sequence of sequences of items, one sequence per row.
- hasHeader: True if the first row consists of the columns' names.
- headerChar: Character to be used for the row separator line
(if hasHeader==True or separateRows==True).
- delim: The column delimiter.
- justify: Determines how are data justified in their column.
Valid values are 'left','right' and 'center'.
- separateRows: True if rows are to be separated by a line
of 'headerChar's.
- prefix: A string prepended to each printed row.
- postfix: A string appended to each printed row.
- wrapfunc: A function f(text) for wrapping text; each element in
the table is first wrapped by this function."""# closure for breaking logical rows to physical, using wrapfuncdef rowWrapper(row):
newRows =[wrapfunc(item).split('\n')for item in row]return[[substr or''for substr in item]for item in map(None,*newRows)]# break each logical row into one or more physical ones
logicalRows =[rowWrapper(row)for row in rows]# columns of physical rows
columns = map(None,*reduce(operator.add,logicalRows))# get the maximum of each column by the string length of its items
maxWidths =[max([len(str(item))for item in column])for column in columns]
rowSeparator = headerChar *(len(prefix)+ len(postfix)+ sum(maxWidths)+ \
len(delim)*(len(maxWidths)-1))# select the appropriate justify method
justify ={'center':str.center,'right':str.rjust,'left':str.ljust}[justify.lower()]
output=cStringIO.StringIO()if separateRows:print>> output, rowSeparator
for physicalRows in logicalRows:for row in physicalRows:print>> output, \
prefix \
+ delim.join([justify(str(item),width)for(item,width)in zip(row,maxWidths)]) \
+ postfix
if separateRows or hasHeader:print>> output, rowSeparator; hasHeader=Falsereturn output.getvalue()# written by Mike Brown# http://aspn.activestate.com/ASPN/Cookbook/Python/Recipe/148061def wrap_onspace(text, width):"""
A word-wrap function that preserves existing line breaks
and most spaces in the text. Expects that existing line
breaks are posix newlines (\n).
"""return reduce(lambda line, word, width=width:'%s%s%s'%(line,' \n'[(len(line[line.rfind('\n')+1:])+ len(word.split('\n',1)[0])>= width)],
word),
text.split(' '))import re
def wrap_onspace_strict(text, width):"""Similar to wrap_onspace, but enforces the width constraint:
words longer than width are split."""
wordRegex = re.compile(r'\S{'+str(width)+r',}')return wrap_onspace(wordRegex.sub(lambda m: wrap_always(m.group(),width),text),width)import math
def wrap_always(text, width):"""A simple word-wrap function that wraps text on exactly width characters.
It doesn't split the text in words."""return'\n'.join([ text[width*i:width*(i+1)] \
for i in xrange(int(math.ceil(1.*len(text)/width)))])if __name__ =='__main__':
labels =('First Name','Last Name','Age','Position')
data = \
'''John,Smith,24,Software Engineer
Mary,Brohowski,23,Sales Manager
Aristidis,Papageorgopoulos,28,Senior Reseacher'''
rows =[row.strip().split(',')for row in data.splitlines()]print'Without wrapping function\n'print indent([labels]+rows, hasHeader=True)# test indent with different wrapping functions
width =10for wrapper in(wrap_always,wrap_onspace,wrap_onspace_strict):print'Wrapping function: %s(x,width=%d)\n'%(wrapper.__name__,width)print indent([labels]+rows, hasHeader=True, separateRows=True,
prefix='| ', postfix=' |',
wrapfunc=lambda x: wrapper(x,width))# output:##Without wrapping function##First Name | Last Name | Age | Position #-------------------------------------------------------#John | Smith | 24 | Software Engineer#Mary | Brohowski | 23 | Sales Manager #Aristidis | Papageorgopoulos | 28 | Senior Reseacher ##Wrapping function: wrap_always(x,width=10)##----------------------------------------------#| First Name | Last Name | Age | Position |#----------------------------------------------#| John | Smith | 24 | Software E |#| | | | ngineer |#----------------------------------------------#| Mary | Brohowski | 23 | Sales Mana |#| | | | ger |#----------------------------------------------#| Aristidis | Papageorgo | 28 | Senior Res |#| | poulos | | eacher |#----------------------------------------------##Wrapping function: wrap_onspace(x,width=10)##---------------------------------------------------#| First Name | Last Name | Age | Position |#---------------------------------------------------#| John | Smith | 24 | Software |#| | | | Engineer |#---------------------------------------------------#| Mary | Brohowski | 23 | Sales |#| | | | Manager |#---------------------------------------------------#| Aristidis | Papageorgopoulos | 28 | Senior |#| | | | Reseacher |#---------------------------------------------------##Wrapping function: wrap_onspace_strict(x,width=10)##---------------------------------------------#| First Name | Last Name | Age | Position |#---------------------------------------------#| John | Smith | 24 | Software |#| | | | Engineer |#---------------------------------------------#| Mary | Brohowski | 23 | Sales |#| | | | Manager |#---------------------------------------------#| Aristidis | Papageorgo | 28 | Senior |#| | poulos | | Reseacher |#---------------------------------------------
'''
From http://code.activestate.com/recipes/267662-table-indentation/
PSF License
'''
import cStringIO,operator
def indent(rows, hasHeader=False, headerChar='-', delim=' | ', justify='left',
separateRows=False, prefix='', postfix='', wrapfunc=lambda x:x):
"""Indents a table by column.
- rows: A sequence of sequences of items, one sequence per row.
- hasHeader: True if the first row consists of the columns' names.
- headerChar: Character to be used for the row separator line
(if hasHeader==True or separateRows==True).
- delim: The column delimiter.
- justify: Determines how are data justified in their column.
Valid values are 'left','right' and 'center'.
- separateRows: True if rows are to be separated by a line
of 'headerChar's.
- prefix: A string prepended to each printed row.
- postfix: A string appended to each printed row.
- wrapfunc: A function f(text) for wrapping text; each element in
the table is first wrapped by this function."""
# closure for breaking logical rows to physical, using wrapfunc
def rowWrapper(row):
newRows = [wrapfunc(item).split('\n') for item in row]
return [[substr or '' for substr in item] for item in map(None,*newRows)]
# break each logical row into one or more physical ones
logicalRows = [rowWrapper(row) for row in rows]
# columns of physical rows
columns = map(None,*reduce(operator.add,logicalRows))
# get the maximum of each column by the string length of its items
maxWidths = [max([len(str(item)) for item in column]) for column in columns]
rowSeparator = headerChar * (len(prefix) + len(postfix) + sum(maxWidths) + \
len(delim)*(len(maxWidths)-1))
# select the appropriate justify method
justify = {'center':str.center, 'right':str.rjust, 'left':str.ljust}[justify.lower()]
output=cStringIO.StringIO()
if separateRows: print >> output, rowSeparator
for physicalRows in logicalRows:
for row in physicalRows:
print >> output, \
prefix \
+ delim.join([justify(str(item),width) for (item,width) in zip(row,maxWidths)]) \
+ postfix
if separateRows or hasHeader: print >> output, rowSeparator; hasHeader=False
return output.getvalue()
# written by Mike Brown
# http://aspn.activestate.com/ASPN/Cookbook/Python/Recipe/148061
def wrap_onspace(text, width):
"""
A word-wrap function that preserves existing line breaks
and most spaces in the text. Expects that existing line
breaks are posix newlines (\n).
"""
return reduce(lambda line, word, width=width: '%s%s%s' %
(line,
' \n'[(len(line[line.rfind('\n')+1:])
+ len(word.split('\n',1)[0]
) >= width)],
word),
text.split(' ')
)
import re
def wrap_onspace_strict(text, width):
"""Similar to wrap_onspace, but enforces the width constraint:
words longer than width are split."""
wordRegex = re.compile(r'\S{'+str(width)+r',}')
return wrap_onspace(wordRegex.sub(lambda m: wrap_always(m.group(),width),text),width)
import math
def wrap_always(text, width):
"""A simple word-wrap function that wraps text on exactly width characters.
It doesn't split the text in words."""
return '\n'.join([ text[width*i:width*(i+1)] \
for i in xrange(int(math.ceil(1.*len(text)/width))) ])
if __name__ == '__main__':
labels = ('First Name', 'Last Name', 'Age', 'Position')
data = \
'''John,Smith,24,Software Engineer
Mary,Brohowski,23,Sales Manager
Aristidis,Papageorgopoulos,28,Senior Reseacher'''
rows = [row.strip().split(',') for row in data.splitlines()]
print 'Without wrapping function\n'
print indent([labels]+rows, hasHeader=True)
# test indent with different wrapping functions
width = 10
for wrapper in (wrap_always,wrap_onspace,wrap_onspace_strict):
print 'Wrapping function: %s(x,width=%d)\n' % (wrapper.__name__,width)
print indent([labels]+rows, hasHeader=True, separateRows=True,
prefix='| ', postfix=' |',
wrapfunc=lambda x: wrapper(x,width))
# output:
#
#Without wrapping function
#
#First Name | Last Name | Age | Position
#-------------------------------------------------------
#John | Smith | 24 | Software Engineer
#Mary | Brohowski | 23 | Sales Manager
#Aristidis | Papageorgopoulos | 28 | Senior Reseacher
#
#Wrapping function: wrap_always(x,width=10)
#
#----------------------------------------------
#| First Name | Last Name | Age | Position |
#----------------------------------------------
#| John | Smith | 24 | Software E |
#| | | | ngineer |
#----------------------------------------------
#| Mary | Brohowski | 23 | Sales Mana |
#| | | | ger |
#----------------------------------------------
#| Aristidis | Papageorgo | 28 | Senior Res |
#| | poulos | | eacher |
#----------------------------------------------
#
#Wrapping function: wrap_onspace(x,width=10)
#
#---------------------------------------------------
#| First Name | Last Name | Age | Position |
#---------------------------------------------------
#| John | Smith | 24 | Software |
#| | | | Engineer |
#---------------------------------------------------
#| Mary | Brohowski | 23 | Sales |
#| | | | Manager |
#---------------------------------------------------
#| Aristidis | Papageorgopoulos | 28 | Senior |
#| | | | Reseacher |
#---------------------------------------------------
#
#Wrapping function: wrap_onspace_strict(x,width=10)
#
#---------------------------------------------
#| First Name | Last Name | Age | Position |
#---------------------------------------------
#| John | Smith | 24 | Software |
#| | | | Engineer |
#---------------------------------------------
#| Mary | Brohowski | 23 | Sales |
#| | | | Manager |
#---------------------------------------------
#| Aristidis | Papageorgo | 28 | Senior |
#| | poulos | | Reseacher |
#---------------------------------------------
import pandas as pd
l =[['a','b','c'],['aaaaaaaaaa','b','c'],['a','bbbbbbbbbb','c']]
df = pd.DataFrame(l)print(df)0120 a b c
1 aaaaaaaaaa b c
2 a bbbbbbbbbb c
import pandas as pd
l = [['a', 'b', 'c'], ['aaaaaaaaaa', 'b', 'c'], ['a', 'bbbbbbbbbb', 'c']]
df = pd.DataFrame(l)
print(df)
0 1 2
0 a b c
1 aaaaaaaaaa b c
2 a bbbbbbbbbb c
To remove index and header values to create output what you want you could use to_string method:
result = df.to_string(index=False, header=False)
print(result)
a b c
aaaaaaaaaa b c
a bbbbbbbbbb c
Scolp is a new library that lets you pretty print streaming columnar data easily while auto-adjusting column width.
(Disclaimer: I am the author)
回答 9
这将基于其他答案中使用的最大度量设置独立的,最适合的列宽。
data =[['a','b','c'],['aaaaaaaaaa','b','c'],['a','bbbbbbbbbb','c']]
padding =2
col_widths =[max(len(w)for w in[r[cn]for r in data])+ padding for cn in range(len(data[0]))]
format_string ="{{:{}}}{{:{}}}{{:{}}}".format(*col_widths)for row in data:print(format_string.format(*row))
This sets independent, best-fit column widths based on the max-metric used in other answers.
data = [['a', 'b', 'c'], ['aaaaaaaaaa', 'b', 'c'], ['a', 'bbbbbbbbbb', 'c']]
padding = 2
col_widths = [max(len(w) for w in [r[cn] for r in data]) + padding for cn in range(len(data[0]))]
format_string = "{{:{}}}{{:{}}}{{:{}}}".format(*col_widths)
for row in data:
print(format_string.format(*row))
Meaning of {0:<30} {1:>35} {2:>35} {3:>35} {4:>20} {5:>20}:
0, 1, 2, 3, 4, 5 -> columns, there are 6 in total in this case
30, 35, 20 -> width of column (note that you’ll have to add length of \033[96m – this for Python is a string as well), just experiment :)
>, < -> justify: right, left (there is = for filling with zeros as well)
If you want to distinct e.g. max value, you’ll have to switch to special Pandas style function, but suppose that’s far enough to present data on terminal window.
A slight variation on a previous answer (I don’t have enough rep to comment on it). The format library lets you specify the width and alignment of an element but not where it starts, ie, you can say “be 20 columns wide” but not “start in column 20”. Which leads to this issue:
@icontract.pre(lambda table:not table or all(len(row)== len(table[0])for row in table))@icontract.post(lambda table, result: result ==""ifnot table elseTrue)@icontract.post(lambda result:not result.endswith("\n"))def format_table(table:List[List[str]])-> str:"""
Format the table as equal-spaced columns.
:param table: rows of cells
:return: table as string
"""
cols = len(table[0])
col_widths =[max(len(row[i])for row in table)for i in range(cols)]
lines =[]# type: List[str]for i, row in enumerate(table):
parts =[]# type: List[str]for cell, width in zip(row, col_widths):
parts.append(cell.ljust(width))
line =" | ".join(parts)
lines.append(line)if i ==0:
border =[]# type: List[str]for width in col_widths:
border.append("-"* width)
lines.append("-+-".join(border))
result ="\n".join(lines)return result
这是一个例子:
>>> table =[['column 0','another column 1'],['00','01'],['10','11']]>>> result = packagery._format_table(table=table)>>>print(result)
column 0| another column 1---------+-----------------00|0110|11
Here is a variation of the Shawn Chin’s answer. The width is fixed per column, not over all columns. There is also a border below the first row and between the columns. (icontract library is used to enforce the contracts.)
@icontract.pre(
lambda table: not table or all(len(row) == len(table[0]) for row in table))
@icontract.post(lambda table, result: result == "" if not table else True)
@icontract.post(lambda result: not result.endswith("\n"))
def format_table(table: List[List[str]]) -> str:
"""
Format the table as equal-spaced columns.
:param table: rows of cells
:return: table as string
"""
cols = len(table[0])
col_widths = [max(len(row[i]) for row in table) for i in range(cols)]
lines = [] # type: List[str]
for i, row in enumerate(table):
parts = [] # type: List[str]
for cell, width in zip(row, col_widths):
parts.append(cell.ljust(width))
line = " | ".join(parts)
lines.append(line)
if i == 0:
border = [] # type: List[str]
for width in col_widths:
border.append("-" * width)
lines.append("-+-".join(border))
result = "\n".join(lines)
return result
import io
import math
import operator
import re
import functools
from itertools import zip_longest
def indent(
rows,
has_header=False,
header_char="-",
delim=" | ",
justify="left",
separate_rows=False,
prefix="",
postfix="",
wrapfunc=lambda x: x,):"""Indents a table by column.
- rows: A sequence of sequences of items, one sequence per row.
- hasHeader: True if the first row consists of the columns' names.
- headerChar: Character to be used for the row separator line
(if hasHeader==True or separateRows==True).
- delim: The column delimiter.
- justify: Determines how are data justified in their column.
Valid values are 'left','right' and 'center'.
- separateRows: True if rows are to be separated by a line
of 'headerChar's.
- prefix: A string prepended to each printed row.
- postfix: A string appended to each printed row.
- wrapfunc: A function f(text) for wrapping text; each element in
the table is first wrapped by this function."""# closure for breaking logical rows to physical, using wrapfuncdef row_wrapper(row):
new_rows =[wrapfunc(item).split("\n")for item in row]return[[substr or""for substr in item]for item in zip_longest(*new_rows)]# break each logical row into one or more physical ones
logical_rows =[row_wrapper(row)for row in rows]# columns of physical rows
columns = zip_longest(*functools.reduce(operator.add, logical_rows))# get the maximum of each column by the string length of its items
max_widths =[max([len(str(item))for item in column])for column in columns]
row_separator = header_char *(
len(prefix)+ len(postfix)+ sum(max_widths)+ len(delim)*(len(max_widths)-1))# select the appropriate justify method
justify ={"center": str.center,"right": str.rjust,"left": str.ljust}[
justify.lower()]
output = io.StringIO()if separate_rows:print(output, row_separator)for physicalRows in logical_rows:for row in physicalRows:print( output, prefix + delim.join([justify(str(item), width)for(item, width)in zip(row, max_widths)])+ postfix)if separate_rows or has_header:print(output, row_separator)
has_header =Falsereturn output.getvalue()# written by Mike Brown# http://aspn.activestate.com/ASPN/Cookbook/Python/Recipe/148061def wrap_onspace(text, width):"""
A word-wrap function that preserves existing line breaks
and most spaces in the text. Expects that existing line
breaks are posix newlines (\n).
"""return functools.reduce(lambda line, word, i_width=width:"%s%s%s"%(
line," \n"[(
len(line[line.rfind("\n")+1:])+ len(word.split("\n",1)[0])>= i_width
)],
word,),
text.split(" "),)def wrap_onspace_strict(text, i_width):"""Similar to wrap_onspace, but enforces the width constraint:
words longer than width are split."""
word_regex = re.compile(r"\S{"+ str(i_width)+ r",}")return wrap_onspace(
word_regex.sub(lambda m: wrap_always(m.group(), i_width), text), i_width
)def wrap_always(text, width):"""A simple word-wrap function that wraps text on exactly width characters.
It doesn't split the text in words."""return"\n".join([
text[width * i : width *(i +1)]for i in range(int(math.ceil(1.0* len(text)/ width)))])if __name__ =="__main__":
labels =("First Name","Last Name","Age","Position")
data ="""John,Smith,24,Software Engineer
Mary,Brohowski,23,Sales Manager
Aristidis,Papageorgopoulos,28,Senior Reseacher"""
rows =[row.strip().split(",")for row in data.splitlines()]print("Without wrapping function\n")print(indent([labels]+ rows, has_header=True))# test indent with different wrapping functions
width =10for wrapper in(wrap_always, wrap_onspace, wrap_onspace_strict):print("Wrapping function: %s(x,width=%d)\n"%(wrapper.__name__, width))print(
indent([labels]+ rows,
has_header=True,
separate_rows=True,
prefix="| ",
postfix=" |",
wrapfunc=lambda x: wrapper(x, width),))# output:## Without wrapping function## First Name | Last Name | Age | Position# -------------------------------------------------------# John | Smith | 24 | Software Engineer# Mary | Brohowski | 23 | Sales Manager# Aristidis | Papageorgopoulos | 28 | Senior Reseacher## Wrapping function: wrap_always(x,width=10)## ----------------------------------------------# | First Name | Last Name | Age | Position |# ----------------------------------------------# | John | Smith | 24 | Software E |# | | | | ngineer |# ----------------------------------------------# | Mary | Brohowski | 23 | Sales Mana |# | | | | ger |# ----------------------------------------------# | Aristidis | Papageorgo | 28 | Senior Res |# | | poulos | | eacher |# ----------------------------------------------## Wrapping function: wrap_onspace(x,width=10)## ---------------------------------------------------# | First Name | Last Name | Age | Position |# ---------------------------------------------------# | John | Smith | 24 | Software |# | | | | Engineer |# ---------------------------------------------------# | Mary | Brohowski | 23 | Sales |# | | | | Manager |# ---------------------------------------------------# | Aristidis | Papageorgopoulos | 28 | Senior |# | | | | Reseacher |# ---------------------------------------------------## Wrapping function: wrap_onspace_strict(x,width=10)## ---------------------------------------------# | First Name | Last Name | Age | Position |# ---------------------------------------------# | John | Smith | 24 | Software |# | | | | Engineer |# ---------------------------------------------# | Mary | Brohowski | 23 | Sales |# | | | | Manager |# ---------------------------------------------# | Aristidis | Papageorgo | 28 | Senior |# | | poulos | | Reseacher |# ---------------------------------------------
updated @Franck Dernoncourt fancy recipe to be python 3 and PEP8 compliant
import io
import math
import operator
import re
import functools
from itertools import zip_longest
def indent(
rows,
has_header=False,
header_char="-",
delim=" | ",
justify="left",
separate_rows=False,
prefix="",
postfix="",
wrapfunc=lambda x: x,
):
"""Indents a table by column.
- rows: A sequence of sequences of items, one sequence per row.
- hasHeader: True if the first row consists of the columns' names.
- headerChar: Character to be used for the row separator line
(if hasHeader==True or separateRows==True).
- delim: The column delimiter.
- justify: Determines how are data justified in their column.
Valid values are 'left','right' and 'center'.
- separateRows: True if rows are to be separated by a line
of 'headerChar's.
- prefix: A string prepended to each printed row.
- postfix: A string appended to each printed row.
- wrapfunc: A function f(text) for wrapping text; each element in
the table is first wrapped by this function."""
# closure for breaking logical rows to physical, using wrapfunc
def row_wrapper(row):
new_rows = [wrapfunc(item).split("\n") for item in row]
return [[substr or "" for substr in item] for item in zip_longest(*new_rows)]
# break each logical row into one or more physical ones
logical_rows = [row_wrapper(row) for row in rows]
# columns of physical rows
columns = zip_longest(*functools.reduce(operator.add, logical_rows))
# get the maximum of each column by the string length of its items
max_widths = [max([len(str(item)) for item in column]) for column in columns]
row_separator = header_char * (
len(prefix) + len(postfix) + sum(max_widths) + len(delim) * (len(max_widths) - 1)
)
# select the appropriate justify method
justify = {"center": str.center, "right": str.rjust, "left": str.ljust}[
justify.lower()
]
output = io.StringIO()
if separate_rows:
print(output, row_separator)
for physicalRows in logical_rows:
for row in physicalRows:
print( output, prefix + delim.join(
[justify(str(item), width) for (item, width) in zip(row, max_widths)]
) + postfix)
if separate_rows or has_header:
print(output, row_separator)
has_header = False
return output.getvalue()
# written by Mike Brown
# http://aspn.activestate.com/ASPN/Cookbook/Python/Recipe/148061
def wrap_onspace(text, width):
"""
A word-wrap function that preserves existing line breaks
and most spaces in the text. Expects that existing line
breaks are posix newlines (\n).
"""
return functools.reduce(
lambda line, word, i_width=width: "%s%s%s"
% (
line,
" \n"[
(
len(line[line.rfind("\n") + 1 :]) + len(word.split("\n", 1)[0])
>= i_width
)
],
word,
),
text.split(" "),
)
def wrap_onspace_strict(text, i_width):
"""Similar to wrap_onspace, but enforces the width constraint:
words longer than width are split."""
word_regex = re.compile(r"\S{" + str(i_width) + r",}")
return wrap_onspace(
word_regex.sub(lambda m: wrap_always(m.group(), i_width), text), i_width
)
def wrap_always(text, width):
"""A simple word-wrap function that wraps text on exactly width characters.
It doesn't split the text in words."""
return "\n".join(
[
text[width * i : width * (i + 1)]
for i in range(int(math.ceil(1.0 * len(text) / width)))
]
)
if __name__ == "__main__":
labels = ("First Name", "Last Name", "Age", "Position")
data = """John,Smith,24,Software Engineer
Mary,Brohowski,23,Sales Manager
Aristidis,Papageorgopoulos,28,Senior Reseacher"""
rows = [row.strip().split(",") for row in data.splitlines()]
print("Without wrapping function\n")
print(indent([labels] + rows, has_header=True))
# test indent with different wrapping functions
width = 10
for wrapper in (wrap_always, wrap_onspace, wrap_onspace_strict):
print("Wrapping function: %s(x,width=%d)\n" % (wrapper.__name__, width))
print(
indent(
[labels] + rows,
has_header=True,
separate_rows=True,
prefix="| ",
postfix=" |",
wrapfunc=lambda x: wrapper(x, width),
)
)
# output:
#
# Without wrapping function
#
# First Name | Last Name | Age | Position
# -------------------------------------------------------
# John | Smith | 24 | Software Engineer
# Mary | Brohowski | 23 | Sales Manager
# Aristidis | Papageorgopoulos | 28 | Senior Reseacher
#
# Wrapping function: wrap_always(x,width=10)
#
# ----------------------------------------------
# | First Name | Last Name | Age | Position |
# ----------------------------------------------
# | John | Smith | 24 | Software E |
# | | | | ngineer |
# ----------------------------------------------
# | Mary | Brohowski | 23 | Sales Mana |
# | | | | ger |
# ----------------------------------------------
# | Aristidis | Papageorgo | 28 | Senior Res |
# | | poulos | | eacher |
# ----------------------------------------------
#
# Wrapping function: wrap_onspace(x,width=10)
#
# ---------------------------------------------------
# | First Name | Last Name | Age | Position |
# ---------------------------------------------------
# | John | Smith | 24 | Software |
# | | | | Engineer |
# ---------------------------------------------------
# | Mary | Brohowski | 23 | Sales |
# | | | | Manager |
# ---------------------------------------------------
# | Aristidis | Papageorgopoulos | 28 | Senior |
# | | | | Reseacher |
# ---------------------------------------------------
#
# Wrapping function: wrap_onspace_strict(x,width=10)
#
# ---------------------------------------------
# | First Name | Last Name | Age | Position |
# ---------------------------------------------
# | John | Smith | 24 | Software |
# | | | | Engineer |
# ---------------------------------------------
# | Mary | Brohowski | 23 | Sales |
# | | | | Manager |
# ---------------------------------------------
# | Aristidis | Papageorgo | 28 | Senior |
# | | poulos | | Reseacher |
# ---------------------------------------------
回答 15
我知道这个问题很旧,但是我不了解Antak的答案,也不想使用库,所以我推出了自己的解决方案。
解决方案假定记录是2D数组,记录的长度都相同,并且字段都是字符串。
def stringifyRecords(records):
column_widths =[0]* len(records[0])for record in records:for i, field in enumerate(record):
width = len(field)if width > column_widths[i]: column_widths[i]= width
s =""for record in records:for column_width, field in zip(column_widths, record):
s += field.ljust(column_width+1)
s +="\n"return s
I realize this question is old but I didn’t understand Antak’s answer and didn’t want to use a library so I rolled my own solution.
Solution assumes records is a 2D array, records are all the same length, and that fields are all strings.
def stringifyRecords(records):
column_widths = [0] * len(records[0])
for record in records:
for i, field in enumerate(record):
width = len(field)
if width > column_widths[i]: column_widths[i] = width
s = ""
for record in records:
for column_width, field in zip(column_widths, record):
s += field.ljust(column_width+1)
s += "\n"
return s
ok so that’s simplified but you get the idea. Now thing might not actually be in the list, in which case I want to pass -1 as thing_index. In other languages this is what you’d expect index() to return if it couldn’t find the element. In fact it throws a ValueError.
But this feels dirty, plus I don’t know if ValueError could be raised for some other reason. I came up with the following solution based on generator functions, but it seems a little complex:
thing_index = ( [(i for i in xrange(len(thing_list)) if thing_list[i]==thing)] or [-1] )[0]
Is there a cleaner way to achieve the same thing? Let’s assume the list isn’t sorted.
There is nothing “dirty” about using try-except clause. This is the pythonic way. ValueError will be raised by the .index method only, because it’s the only code you have there!
To answer the comment:
In Python, easier to ask forgiveness than to get permission philosophy is well established, and noindex will not raise this type of error for any other issues. Not that I can think of any.
回答 1
thing_index = thing_list.index(elem)if elem in thing_list else-1
The dict type has a get function, where if the key doesn’t exist in the dictionary, the 2nd argument to get is the value that it should return. Similarly there is setdefault, which returns the value in the dict if the key exists, otherwise it sets the value according to your default parameter and then returns your default parameter.
You could extend the list type to have a getindexdefault method.
This issue is one of language philosophy. In Java for example there has always been a tradition that exceptions should really only be used in “exceptional circumstances” that is when errors have happened, rather than for flow control. In the beginning this was for performance reasons as Java exceptions were slow but now this has become the accepted style.
In contrast Python has always used exceptions to indicate normal program flow, like raising a ValueError as we are discussing here. There is nothing “dirty” about this in Python style and there are many more where that came from. An even more common example is StopIteration exception which is raised by an iterator‘s next() method to signal that there are no further values.
li =[1,2,3,4,5]# create list
li = dict(zip(li,range(len(li))))# convert List To Dict print( li )# {1: 0, 2: 1, 3: 2, 4:3 , 5: 4}
li.get(20)# None
li.get(1)# 0
Rather than expose something so implementation-dependent like a list index in a function interface, pass the collection and the thing and let otherfunction deal with the “test for membership” issues. If otherfunction is written to be collection-type-agnostic, then it would probably start with:
if thing in thing_collection:
... proceed with operation on thing
which will work if thing_collection is a list, tuple, set, or dict.
This is possibly clearer than:
if thing_index != MAGIC_VALUE_INDICATING_NOT_A_MEMBER:
which is the code you already have in otherfunction.
回答 8
像这样:
temp_inx =(L +[x]).index(x)
inx = temp_inx if temp_inx < len(L)else-1
I have the same issue with the “.index()” method on lists. I have no issue with the fact that it throws an exception but I strongly disagree with the fact that it’s a non-descriptive ValueError. I could understand if it would’ve been an IndexError, though.
I can see why returning “-1” would be an issue too because it’s a valid index in Python. But realistically, I never expect a “.index()” method to return a negative number.
Here goes a one liner (ok, it’s a rather long line …), goes through the list exactly once and returns “None” if the item isn’t found. It would be trivial to rewrite it to return -1, should you so desire.
indexOf = lambda list, thing: \
reduce(lambda acc, (idx, elem): \
idx if (acc is None) and elem == thing else acc, list, None)
I don’t know why you should think it is dirty… because of the exception? if you want a oneliner, here it is:
thing_index = thing_list.index(elem) if thing_list.count(elem) else -1
but i would advise against using it; I think Ross Rogers solution is the best, use an object to encapsulate your desiderd behaviour, don’t try pushing the language to its limits at the cost of readability.
回答 11
我建议:
if thing in thing_list:
list_index =-1else:
list_index = thing_list.index(thing)
I understand that they are both essentially the same thing, but in terms of style, which is the better (more Pythonic) one to use to create an empty list or dict?
In the case of difference between [] and list(), there is a pitfall that I haven’t seen anyone else point out.
If you use a dictionary as a member of the list, the two will give entirely different results:
In [1]: foo_dict = {"1":"foo", "2":"bar"}
In [2]: [foo_dict]
Out [2]: [{'1': 'foo', '2': 'bar'}]
In [3]: list(foo_dict)
Out [3]: ['1', '2']
回答 5
list()和[]的工作方式不同:
>>>def a(p=None):...print(id(p))...>>>for r in range(3):... a([])...139969725291904139969725291904139969725291904>>>for r in range(3):... a(list())...139969725367296139969725367552139969725367616
>>> def a(p):
... print(id(p))
...
>>> for r in range(3):
... a([])
...
139969725291904
139969725291904
139969725291904
>>> for r in range(3):
... a(list())
...
139969725367296
139969725367552
139969725367616
list() always create new object in heap, but [] can reuse memory cell in many reason.
there is one difference in behavior between [] and list() as example below shows. we need to use list() if we want to have the list of numbers returned, otherwise we get a map object! No sure how to explain it though.
The + operation adds the array elements to the original array. The array.append operation inserts the array (or any object) into the end of the original array, which results in a reference to self in that spot (hence the infinite recursion).
The difference here is that the + operation acts specific when you add an array (it’s overloaded like others, see this chapter on sequences) by concatenating the element. The append-method however does literally what you ask: append the object on the right-hand side that you give it (the array or any other object), instead of taking its elements.
An alternative
Use extend() if you want to use a function that acts similar to the + operator (as others have shown here as well). It’s not wise to do the opposite: to try to mimic append with the + operator for lists (see my earlier link on why).
Little history
For fun, a little history: the birth of the array module in Python in February 1993. it might surprise you, but arrays were added way after sequences and lists came into existence.
The concatenation operator + is a binary infix operator which, when applied to lists, returns a new list containing all the elements of each of its two operands. The list.append() method is a mutator on list which appends its single object argument (in your specific example the list c) to the subject list. In your example this results in c appending a reference to itself (hence the infinite recursion).
An alternative to ‘+’ concatenation
The list.extend() method is also a mutator method which concatenates its sequence argument with the subject list. Specifically, it appends each of the elements of sequence in iteration order.
An aside
Being an operator, + returns the result of the expression as a new value. Being a non-chaining mutator method, list.extend() modifies the subject list in-place and returns nothing.
Arrays
I’ve added this due to the potential confusion which the Abel’s answer above may cause by mixing the discussion of lists, sequences and arrays.Arrays were added to Python after sequences and lists, as a more efficient way of storing arrays of integral data types. Do not confuse arrays with lists. They are not the same.
Arrays are sequence types and behave very much like lists, except that the type of objects stored in them is constrained. The type is specified at object creation time by using a type code, which is a single character.
Python lists are heterogeneous that is the elements in the same list can be any type of object. The expression: c.append(c) appends the object c what ever it may be to the list. In the case it makes the list itself a member of the list.
The expression c += c adds two lists together and assigns the result to the variable c. The overloaded + operator is defined on lists to create a new list whose contents are the elements in the first list and the elements in the second list.
So these are really just different expressions used to do different things by design.
list.append(x)Add an item to the end of the list; equivalent to a[len(a):]=[x].
list.extend(L)Extend the list by appending all the items in the given list; equivalent to a[len(a):]= L.
list.insert(i, x)Insert an item at a given position.The first argument is the index of the element before which to insert, so a.insert(0, x) inserts at the front of the list,and a.insert(len(a), x)is equivalent to a.append(x).
The method you’re looking for is extend(). From the Python documentation:
list.append(x)
Add an item to the end of the list; equivalent to a[len(a):] = [x].
list.extend(L)
Extend the list by appending all the items in the given list; equivalent to a[len(a):] = L.
list.insert(i, x)
Insert an item at a given position. The first argument is the index of the element before which to insert, so a.insert(0, x) inserts at the front of the list, and a.insert(len(a), x) is equivalent to a.append(x).
Return a list of tuples, where each tuple contains the i-th element
from each of the argument sequences. The returned list is truncated
in length to the length of the shortest argument sequence.
setup ='elements = [(1,1,1) for _ in range(100000)];from operator import itemgetter'
method1 ='[x[1] for x in elements]'
method2 ='map(itemgetter(1), elements)'import timeit
t = timeit.Timer(method1, setup)print('Method 1: '+ str(t.timeit(100)))
t = timeit.Timer(method2, setup)print('Method 2: '+ str(t.timeit(100)))
Found this as I was searching for which way is fastest to pull the second element of a 2-tuple list. Not what I wanted but ran same test as shown with a 3rd method plus test the zip method
setup = 'elements = [(1,1) for _ in range(100000)];from operator import itemgetter'
method1 = '[x[1] for x in elements]'
method2 = 'map(itemgetter(1), elements)'
method3 = 'dict(elements).values()'
method4 = 'zip(*elements)[1]'
import timeit
t = timeit.Timer(method1, setup)
print('Method 1: ' + str(t.timeit(100)))
t = timeit.Timer(method2, setup)
print('Method 2: ' + str(t.timeit(100)))
t = timeit.Timer(method3, setup)
print('Method 3: ' + str(t.timeit(100)))
t = timeit.Timer(method4, setup)
print('Method 4: ' + str(t.timeit(100)))
Method 1: 0.618785858154
Method 2: 0.711684942245
Method 3: 0.298138141632
Method 4: 1.32586884499
So over twice as fast if you have a 2 tuple pair to just convert to a dict and take the values.
回答 4
Python 3.6的计时,用于从2元组列表中提取第二个元素。
另外,添加了numpy数组方法,该方法更易于阅读(但可以说比列表理解更简单)。
from operator import itemgetter
elements =[(1,1)for _ in range(100000)]%timeit second =[x[1]for x in elements]%timeit second = list(map(itemgetter(1), elements))%timeit second = dict(elements).values()%timeit second = list(zip(*elements))[1]%timeit second = np.array(elements)[:,1]
和时间:
list comprehension:4.73 ms ±206µs per loop
list(map):5.3 ms ±167µs per loop
dict:2.25 ms ±103µs per loop
list(zip)5.2 ms ±252µs per loop
numpy array:28.7 ms ±1.88 ms per loop
Timings for Python 3.6 for extracting the second element from a 2-tuple list.
Also, added numpy array method, which is simpler to read (but arguably simpler than the list comprehension).
from operator import itemgetter
elements = [(1,1) for _ in range(100000)]
%timeit second = [x[1] for x in elements]
%timeit second = list(map(itemgetter(1), elements))
%timeit second = dict(elements).values()
%timeit second = list(zip(*elements))[1]
%timeit second = np.array(elements)[:,1]
and the timings:
list comprehension: 4.73 ms ± 206 µs per loop
list(map): 5.3 ms ± 167 µs per loop
dict: 2.25 ms ± 103 µs per loop
list(zip) 5.2 ms ± 252 µs per loop
numpy array: 28.7 ms ± 1.88 ms per loop
Note that map() and zip() do not return a list anymore, hence the explicit conversion.
>>>from itertools import chain, islice
>>> elements =[(1,1,1),(2,3,7),(3,5,10)]>>> list(chain.from_iterable(islice(item,1,2)for item in elements))[1,3,5]
当您需要多个元素时,这可能会很有用:
>>> elements =[(0,1,2,3,4,5),(10,11,12,13,14,15),(20,21,22,23,24,25)]>>> list(chain.from_iterable(islice(tuple_,2,5)for tuple_ in elements))[2,3,4,12,13,14,22,23,24]