python nested list comprehension string concatenation - python

I have a list of lists in python looking like this:
[['a', 'b'], ['c', 'd']]
I want to come up with a string like this:
a,b;c,d
So the lists should be separated with a ; and the values of the same list should be separated with a ,
So far I tried ','.join([y for x in test for y in x]) which returns a,b,c,d. Not quite there, yet, as you can see.

";".join([','.join(x) for x in a])

>>> ';'.join(','.join(x) for x in [['a', 'b'], ['c', 'd']])
'a,b;c,d'

To do it functionally you could use map:
l = [['a', 'b'], ['c', 'd']]
print(";".join(map(".".join, l)))
a.b;c.d

Related

Joining values of a list inside another list into a string

Im trying to join the letters as a string that's inside the list which is also inside the list. So for example, it looks like this [['a', 'b', 'c'], ['d', 'e', 'f']] however I want the result to look like 'ad be cf' which is basically taking the element that lies in the same position in the list. I know how to join the elements into a list that can look like 'abcdef', however, i don't know which I could add in order to return a string that looks like above.
Any advice would be thankful!
string = ''
new_grid = []
for a in grid:
for b in a:
string += b
return string
When you want to transpose lists into columns, you typically reach for zip(). For example:
l = [['a', 'b', 'c'], ['d', 'e', 'f']]
# make a list of columns
substrings = ["".join(sub) for sub in zip(*l)]
#['ad', 'be', 'cf']
print(" ".join(substrings))
# alternatively print(*substrings, sep=" ")
# ad be cf
This works:
my_list = [['a', 'b', 'c'], ['d', 'e', 'f']]
sorted_list = [list(pair) for pair in zip(my_list[0], my_list[1])]
for i in range(3):
string = ''.join(sorted_list[i])
print(string, end=" ")
First, we are pairing each individual list to its corresponding value using [zip][1], then we are joining it into a string, and printing it out.
This solution may not be the most efficient, but it's simple to understand.
Another quick solution without zip could look like this:
my_list = [['a', 'b', 'c'], ['d', 'e', 'f']]
sorted_list = list(map(lambda a, b: a + b, my_list[0], my_list[1]))
print(" ".join(sorted_list))

How to Check if Element exists in Second Sublist?

If I had a list like this:
L = [
['a', 'b'],
['c', 'f'],
['d', 'e']
]
I know that I could check if e.g. 'f' was contained in any of the sub lists by using any in the following way:
if any('f' in sublist for sublist in L) # True
But how would I go about searching through second sub lists, i.e. if the list was initialized the following way:
L = [
[
['a', 'b'],
['c', 'f'],
['d', 'e']
],
[
['z', 'i', 'l'],
['k']
]
]
I tried chaining the for in expressions like this:
if any('f' in second_sublist for second_sublist in sublist for sublist in L)
However, this crashes because name 'sublist' is not defined.
First write your logic as a regular for loop:
for first_sub in L:
for second_sub in first_sub:
if 'f' in second_sub:
print('Match!')
break
Then rewrite as a generator expression with the for statements in the same order:
any('f' in second_sub for first_sub in L for second_sub in first_sub)
If you don't need to know where 'f' is located you can leverage itertools here as well.
import itertools
any('f' in x for x in itertools.chain.from_iterable(l))
This will flatten your nested lists and evaluate each list separately. The benefit here is if you have three nested lists this solution would still function without having to continue writing nest for loops.

Replacing an element in a list with multiple elements

I am trying to modify a list of two lists. For each of the two inside lists, I perform some operation and 'split' them into new lists.
Here is a simple example of what I'm trying to do:
[['a', 'b'], ['c', 'd']] --> [['a'], ['b'], ['c', 'd']]
Currently my algorithm passes ['a', 'b'] to a function that determines whether or not it should be split into [['a'], ['b']] (e.g. based on their correlations). The function returns [['a'], ['b']] which tells me that ['a', 'b'] should be split, or returns ['a', 'b'] (the original list) which indicates that it should not be split.
Currently I have something like this:
blist = [['a', 'b'], ['c', 'd']] #big list
slist = [['a'], ['b']] #small list returned by function
nlist = [items for i in xrange(len(blist)) for items in (slist if i==0 else blist[i])]
This produces [['a'], ['b'], 'c', 'd'] as opposed to the desired output [['a'], ['b'], ['c', 'd']] which does not alter the second list in the original blist. I understand why this is happening--my second loop is also applied to blist[1] in this case, but I am not sure how to fix it as I do not understand list comprehension completely.
A 'pythonic' solution is preferred.
Any feedback would be appreciated, thank you!
EDIT: Like the title suggests, I am trying to 'replace' ['a', 'b'] with ['a'], ['b']. So I would like the 'position' to be the same, having ['a'], ['b'] appear in the original list before ['c', 'd']
RESULTS
Thank you Christian, Paul and schwobaseggl for your solutions! They all work :)
Try
... else [blist[i]])]
to create a list of lists.
You can use slice assignment:
>> l1 = [[1, 2], [3, 4]]
>>> l2 = [[1], [2]]
>>> l1[0:1] = l2
>>> l1
[[1], [2], [3, 4]]
This changes l1, so if you want to keep it make a copy before.
Another way that doesn't change l1 is addition:
>> l1 = [[1, 2], [3, 4]]
>>> l3 = l2 + l1[1:]
>>> l3
[[1], [2], [3, 4]]
You could alter your split function to return structurally adequate lists. Then you can use a comprehension:
def split_or_not(l):
if condition: # split
return [l[:1], l[1:]]
return [l] # wrap in extra list
# using map
nlist = [x for sub_l in map(split_or_not, blist) for x in sub_l]
# or nested comprehension
nlist = [x for sub_l in (split_or_not(l) for l in blist) for x in sub_l]
Assuming you have the mentioned funtion that decides whether to split an item:
def munch(item):
if item[0] == 'a': # split
return [[item[0]], [item[1]]]
return [item] # don't split
You can use it in s simple for-loop.
nlist = []
for item in blist:
nlist.extend(munch(item))
"Pythonic" is whatever is easy to read and understand. Don't use list comprehensions just because you can.

zip the values from a dictionary [duplicate]

This question already has an answer here:
zip two values from the dictionary in Python
(1 answer)
Closed 6 years ago.
I have a dictionary in python 2.7 that has the following structure:
x = {
'1': ['a', 'b', 'c'],
'2': ['d', 'e', 'f']
}
The length of the value list is always the same and I would like to basically zip the value lists with corresponding values. So, in this case it will create three new lists as:
[['a', 'd'], ['b', 'e'], ['c', 'f']]
I know I can write an awful looking loop to do this but I was wondering if there is a more pythonic way to do this. I need to preserve the order.
You can do the following:
zip(*x.values())
Explanation:
x.values() returns [['a', 'b', 'c'], ['d', 'e', 'f']] (order may change so you might need to sort x first.)
zip([a, b], [c, d]) returns [[a, c], [b, d]]
To expand x.values() into arguments to zip, prepend * to it.
This is single line solves the problem but is likely worse looking than your loop. It loops over the sorted keys and produces a list to pass to zip and then maps over the result converting the tuples into lists.
>>> x = {'1': ['a', 'b', 'c'], '2': ['d', 'e', 'f']}
>>> map(list, zip(*[x[k] for k in sorted(x)]))
[['a', 'd'], ['b', 'e'], ['c', 'f']]
res = list(zip(x['1'], x['2']))
res = list(map(list, res))
An explanation:
zip(x['1'], x['2'])
Creates a zip object that links up your pairs.
res = list(zip(x['1'], x['2']))
That zip object now become a list of tuples.
list(map(list, res))
For each element in res (each tuple), change the data structure from tuple to list, as you requested in your desired output above (map the list data type onto all elements in res). Then, convert that map object into a list to arrive at the final, desired result.

Using append() on transient anonymous lists inside of a list comprehension in Python

I have a nested list that looks like this:
mylist = [['A;B', 'C'], ['D;E', 'F']]
I'd like to have it in the following form:
[['A', 'B', 'C'], ['D', 'E', 'F']]
Figured I'd write a simple list comprehension to do the task:
>>> newlist = [item[0].split(';').append(item[1]) for item in mylist]
>>> newlist
[None, None]
After some experimenting, I found that the error was in trying to use append() on anonymous lists:
>>> type(['A', 'B'])
<class 'list'>
>>> type(['A', 'B'].append('C'))
<class 'NoneType'>
Which seems like a gotcha, considering that you can do things like this:
>>> 'abc'.upper()
'ABC'
Obviously in most cases you could get around this by binding ['A', 'B'] to a variable before calling append(), but how would I make this work inside of a list comprehension? Furthermore, can anyone explain this unintuitive behavior?
[a.split(';') + [b] for a, b in mylist]
The problem is that you are storing the return value of the append() method, which is None.
One solution is to use itertools.chain() and store it in a list like so:
import itertools
mylist = [['A;B', 'C'], ['D;E', 'F']]
newlist = [list(itertools.chain(item[0].split(';'),item[1])) for item in mylist]
print newlist
prints:
[['A', 'B', 'C'], ['D', 'E', 'F']]
As you found out, mutating methods aren't of much use inside a list comprehension because the transient objects disappear immediately.
What works instead is to build-up a list through concatenation:
>>> mylist = [['A;B', 'C'], ['D;E', 'F']]
>>> [first.split(';') + [second] for first, second in mylist]
[['A', 'B', 'C'], ['D', 'E', 'F']]
As Will mentioned, the result of append() will be None, and you actually want the resulting list. Here is one option:
>>> mylist = [['A;B', 'C'], ['D;E', 'F']]
>>> mylist = [item[0].split(';') + [item[1]] for item in mylist]
>>> mylist
[['A', 'B', 'C'], ['D', 'E', 'F']]

Categories

Resources