Suppose I have a list of lists say
A = [[1,1,1,1],[2,2,2,2]]
and I want to create two strings from that to be
'1111'
'2222'
How would we do this in python?
Maybe list comprehension:
>>> A = [[1,1,1,1],[2,2,2,2]]
>>> l=[''.join(map(str,i)) for i in A]
>>> l
['1111', '2222']
>>>
Now you've got it.
This is pretty easily done using join and a list comprehension.
A = [[1,1,1,1],[2,2,2,2]]
a_strings = [''.join(map(str, sub_list)) for sublist in A]
See, join() takes a list of strings and makes a string concatenating all the substrings and the list comprehension I used just loops through them all. Above I combined the 2 together.
On a second thought
map() is actually deemed more efficient (when not using lambda.. etc) and for SOME more readable. I'll just add an approach using map instead of a comprehension.
a_strings = map(''.join(), map(str, A))
This first takes the inner map and makes all the ints > strs then joins all the strs together for every sub-list.
Hopefully this makes things a bit more chewable for ya, each method is close to equivalent such that for this case you could consider them style choices.
Related
i have list of strings
lst = ["/foo/dir/c-.*.txt","/foo/dir2/d-.*.svc","/foo/dir3/es-.*.info"]
and i have prefix string :
/root
is there any pythonic way to add the prefix string to each element in the list
so the end result will look like this:
lst = ["/root/foo/dir/c-.*.txt","/root/foo/dir2/d-.*.svc","/root/foo/dir3/es-.*.info"]
if it can be done without iterating and creating new list ...
used:
List Comprehensions
List comprehensions provide a concise way to create lists. Common
applications are to make new lists where each element is the result of
some operations applied to each member of another sequence or
iterable, or to create a subsequence of those elements that satisfy a
certain condition.
F=Strings
F-strings provide a way to embed expressions inside string literals,
using a minimal syntax. It should be noted that an f-string is really
an expression evaluated at run time, not a constant value. In Python
source code, an f-string is a literal string, prefixed with 'f', which
contains expressions inside braces. The expressions are replaced with
their values.
lst = ["/foo/dir/c-.*.txt","/foo/dir2/d-.*.svc","/foo/dir3/es-.*.info"]
prefix = '/root'
lst =[ f'{prefix}{path}' for path in lst]
print(lst)
I am not sure of pythonic, but this will be also on possible way
list(map(lambda x: '/root' + x, lst))
Here there is comparison between list comp and map List comprehension vs map
Also thanks to #chris-rands learnt one more way without lambda
list(map('/root'.__add__, lst))
Use list comprehensions and string concatenation:
lst = ["/foo/dir/c-.*.txt","/foo/dir2/d-.*.svc","/foo/dir3/es-.*.info"]
print(['/root' + p for p in lst])
# ['/root/foo/dir/c-.*.txt', '/root/foo/dir2/d-.*.svc', '/root/foo/dir3/es-.*.info']
Just simply write:
lst = ["/foo/dir/c-.*.txt","/foo/dir2/d-.*.svc","/foo/dir3/es-.*.info"]
prefix="/root"
res = [prefix + x for x in lst]
print(res)
A simple list comprehension -
lst = ["/foo/dir/c-.*.txt","/foo/dir2/d-.*.svc","/foo/dir3/es-.*.info"]
prefix = '/root'
print([prefix + string for string in lst]) # You can give it a variable if you want
for example, i have a list below,
['Visa', 'Rogers', 'Visa']
if i want to convert it to a list of tuples, like
[('Visa',), ('Rogers',), ('Visa',)]
How can I convert it?
>>> [(x,) for x in ['Visa', 'Rogers', 'Visa']]
[('Visa',), ('Rogers',), ('Visa',)]
simple list comprehension will do the trick. make sure to have the , to specify single item tuples (you will just have the original strings instead)
Doing some kind of operation for each element can be done with map() or list comprehensions:
a = ['Visa', 'Rogers', 'Visa']
b = [(v,) for v in a]
c = map(lambda v: (v,), a)
print(b) # [('Visa',), ('Rogers',), ('Visa',)]
print(c) # [('Visa',), ('Rogers',), ('Visa',)]
Please keep in mind that 1-element-tuples are represented as (value,) to distinguish them from just a grouping/regular parantheses
I have two list of different dictionaries (ListA and ListB).
All dictionaries in listA have field "id" and "external_id"
All dictionaries in listB have field "num" and "external_num"
I need to get all pairs of dictionaries where value of external_id = num and value of external_num = id.
I can achieve that using this code:
for dictA in ListA:
for dictB in ListB:
if dictA["id"] == dictB["external_num"] and dictA["external_id"] == dictB["num"]:
But I saw many beautiful python expressions, and I guess it is possible to get that result more pythonic style, isn't it?
I something like:
res = [A, B for A, B in listA, listB if A['id'] == B['extnum'] and A['ext'] == B['num']]
You are pretty close, but you aren't telling Python how you want to connect the two lists to get the pairs of dictionaries A and B.
If you want to compare all dictionaries in ListA to all in ListB, you need itertools.product:
from itertools import product
res = [A, B for A, B in product(ListA, ListB) if ...]
Alternatively, if you want pairs at the same indices, use zip:
res = [A, B for A, B in zip(ListA, ListB) if ...]
If you don't need the whole list building at once, note that you can use itertools.ifilter to pick the pairs you want:
from itertools import ifilter, product
for A, B in ifilter(lambda (A, B): ...,
product(ListA, ListB)):
# do whatever you want with A and B
(if you do this with zip, use itertools.izip instead to maximise performance).
Notes on Python 3.x:
zip and filter no longer return lists, therefore itertools.izip and itertools.ifilter no longer exist (just as range has pushed out xrange) and you only need product from itertools; and
lambda (A, B): is no longer valid syntax; you will need to write the filtering function to take a single tuple argument lambda t: and e.g. replace A with t[0].
Firstly, for code clarity, I actually would probably go with your first option - I don't think using for loops is particularly un-Pythonic, in this case. However, if you want to try using a list comprehension, there are a few things to be aware of:
Each item returned by the list comprehension needs to be just a singular item. Trying to return A, B is going to give you a SyntaxError. However, you can return either a list or a tuple (or anything else, that is a single object), so something like res = [(A,B) for...] would start working.
Another concern is how you're iterating over these lists - from you first snippet of code, it appears you don't make any assumptions about these lists lining up, meaning: you seem to be ok if the 2nd item in listA matches the 14th item in listB, so long as they match on the appropriate fields. That's perfectly reasonable, but just be aware that means you will need two for loops no matter how you try to do it*. And you still need your comparisons. So, as a list comprehension, you might try:
res = [(A, B) for A in listA for B in listB if A['id']==B['extnum'] and A['extid']==B['num']]
Then, in res, you'll have 0 or more tuples, and each tuple will contain the respective dictionaries you're interested in. To use them:
for tup in res:
A = tup[0]
B = tup[1]
#....
or more concisely (and Pythonically):
for A,B in res:
#...
since Python is smart enough to know that it's yielding an item (the tuple) that has 2 elements, and so it can directly assign them to A and B.
EDIT:* in retrospect, it isn't completely true that you need two forloops, and if your lists are big enough, it may be helpful, performance-wise, to make an intermediate dictionary such as this:
# make a dictionary with key=tuple, value=dictionary
interim = {(A['id'], A['extid']): A for A in listA}
for B in listB:
tup = (B['extnum'], B['num']) ## order matters! match-up with A
if tup in interim:
A = interim[tup]
print(A, B)
and, if the id-extid pair isnot expected to be unique across all items in listA, then you'd want to look into collections.defaultdict with a list... but I'm not sure this still fits in the 'more Pythonic' category anymore.
I realize this is likely overkill for the question you asked, but I couldn't let my 'two for loops' statement stand, since it's not entirely true.
Can one-line loops in Python only be used to build lists? (i.e. list comprehensions), or can they use for more general computing?
For example, I am aware that list comprehensions (~single-line loop) in Python, e.g.
my_list = [ 2*i for i in range(10)]
can also be built with a multi-line loop:
my_list = []
for i in range(10):
my_list.append(2*i)
But can we always transform general multi-line loops into one-line loops?
For example, say we have the following multi-line for loop:
my_array = np.ones(10*10)
for x in range(10):
my_array[x,:] = 0
can we convert it into a single-line loop? More generally:
Q1. Are the two forms functionally equivalent? (i.e. they support the same set of manipulations/operations)
Q2. I think I have read before that one-line loops in Python are vectorized. Is this true? And does this mean that they can iterate faster than multi-line loops?
But can we we always transform general multi-line loops in Python into one-line loops?
The short answer is no.
List comprehensions are good for projections (mapping) and/or filtering.
For example, if you have code like this:
result = []
for x in seq:
if bar(x):
result.append(foo(x))
Then, as you point out, it can benefit from being rewritten as a list comprehension:
result = [foo(x) for f in seq if bar(x)]
However list comprehensions are generally not so good for operations that don't fit into this projection or filtering pattern.
For example if you need to mutate the elements but don't need the result then a list comprehension wouldn't be suitable. The following code would be inconvenient to write as a list comprehension (assuming that both methods return None):
for x in seq:
x.foo() # Modify x
x.bar() # Modify x again
Some operations are not allowed inside a comprehension. An example is breaking out of the loop early if a condition is met:
for x in seq:
if x.foo():
break
else:
x.bar()
One thing I'll point out is that it's not just lists, you can use comprehension to create sets and even dictionaries.
>>> {i**2 for i in range(5)}
set([0, 1, 4, 16, 9])
>>> {i : str(i) for i in range(5)}
{0: '0', 1: '1', 2: '2', 3: '3', 4: '4'}
Also, list comprehension is generally faster than using append numerous times (like your example) because the comprehension is done by underlying C code, as opposed to append, which has the extra Python-layer.
Of course, comprehension has limitations like anything else. If you wanted to perform a larger set of operations on each element of a list/set, then a normal loop might be more appropriate.
if I have a list, is there any way to check if it contains any other lists?
what i mean to say is, I want to know if a list has this strcuture: [] as opposed to this structure [[]]
so, compare [1,2,3,4] to [1,[2,3],4]
this is complicated by the fact that i have a list of strings.
well, phihag's solution seems to be working so far, but what I'm doing is this:
uniqueCrossTabs = list(itertools.chain.from_iterable(uniqueCrossTabs))
in order to flatten a list if it has other lists in it.
But since my list contains strings, if this is done on an already flattened list, I get a list of each character of each string that was in the original list.
This is not the behavior i was looking for. so, checking to see if the list needs to be flattened before flattening is neccessary.
any(isinstance(el, list) for el in input_list)
You can take phihag's answer even further if you actually want a list of all the lists inside the list:
output_list = filter( lambda x: isinstance(x,list), input_list)
lst1 in lst2
Yields True iff lst1 is in lst2.