Merge elements in list of lists - python

I have a list of lists like this:
A = [('b', 'a', 'a', 'a', 'a'), ('b', 'a', 'a', 'a', 'a')]
How can I merge the all elements of each inner list to get result A = ['baaaa', 'baaaa']?
I would prefer to do this outside of a loop, if possible, to speed up the code.

If you don't want to write a loop you can use map and str.join
>>> list(map(''.join, A))
['baaaa', 'baaaa']
However, the loop using a list comprehension is almost as short to write, and I think is clearer:
>>> [''.join(e) for e in A]
['baaaa', 'baaaa']

You can use str.join:
>>> ["".join(t) for t in A]
['baaaa', 'baaaa']
>>>
>>>
>>> list(map(''.join, A) #with map
['baaaa', 'baaaa']
>>>
>>> help(str.join)
Help on method_descriptor:
join(...)
S.join(iterable) -> str
Return a string which is the concatenation of the strings in the
iterable. The separator between elements is S.
>>>

Use the join method of the empty string. This means: "make a string concatenating every element of a tuple (for example ('b', 'a', 'a', 'a', 'a') ) with '' (empty string) between each of them.
Thus, what you are looking for is:
[''.join(x) for x in A]

If you prefer functional programming. You can use the function reduce. Here is how you can achieve the same result using reduce function as follows.
Note that, reduce was a built in function in python 2.7 but in python
3 it is moved to library functools
from functools import reduce
It is only required to import reduce if you are using python 3 else no need to import reduce from functools
A = [('b', 'a', 'a', 'a', 'a'), ('b', 'a', 'a', 'a', 'a')]
result = [reduce(lambda a, b: a+b, i) for i in A]
If you don't want to use loop or even list comprehension, here is another way
list(map(lambda i: reduce(lambda a, b: a+b, i), A))

Related

Apply function to a specific element of tuples in a list

I have a list of tuples and would like to modify (using a function) a specific element of each tuple in the list.
lst = [('a', 'b', 'c32#', 45), ('e', 'f', 'g812', 22)]
Ideally, my function should extract number from the text in [2] and return the list but with the third element modified.
So far I have tried using map and lambda together which only returns a list of the extracted number. Here is my attempt:
def extract_num(txt):
# do sth
return num
new_lst = list(map(lambda el: extract_num(el[2]), lst))
Note: I cannot modify the extract_num func to take a tuple as argument since it is used somewhere else without a tuple.
What about using another function the whole modification logic that uses your extract_num function?
def extract_num(txt):
return 'x'
def alter_tuple(t, pos=2):
return t[:pos]+(extract_num(t[pos]),)+t[pos+1:]
new_lst = [alter_tuple(t) for t in lst]
print(new_lst)
output: [('a', 'b', 'x', 45), ('e', 'f', 'x', 22)]
Do you mean it?
def trim(sentence):
return int(''.join([str(element) for element in sentence if element.isnumeric()]))
print(trim('sdf2dsfd54fsdf'))
>>> 254
print(list(map(lambda el: trim(el[2]), lst)))
>>> [32, 812]

How to change list of tuples to same tuples? [python]

I have list like this:
l = [("a"), ("b"), ("c")]
and i need to have:
l = ("a"), ("b"), ("c")
Someone know some reasonable quick way to do this?
You said you have a list of tuples. What you've shown isn't actually a list of tuples. It's a list of strings:
>>> [("a"), ("b"), ("c")]
['a', 'b', 'c']
>>> type(("a"))
<class 'str'>
I think what you meant was l = [("a",), ("b",), ("c",)]. That's a list of tuples.
To change your list of tuples into a tuple of tuples, you simply do:
>>> tuple(l)
(('a',), ('b',), ('c',))
EDIT - Note, that the following literal syntax:
l = ("a",), ("b",), ("c",)
Is a tuple of tuples.
You say you want
>>> want = ("a"), ("b"), ("c")
>>> want
('a', 'b', 'c')
You say you have
>>> have = [("a"), ("b"), ("c")]
>>> have
['a', 'b', 'c']
Use tuple() to get what you want from what you have:
>>> tuple(have)
('a', 'b', 'c')
>>> tuple(have) == want
True
If you want to make a list of strings to a tuple of strings simply use tuple()
>>> l = [("a"), ("b"), ("c")]
>>> l
['a', 'b', 'c']
>>>
>>> tuple(l)
('a', 'b', 'c')
Is this what you mean?
l = [(1,2),(2,3),(3,4)]
a,b,c = l
# now a = (1,2), b = (2,3), c = (3,4)
Otherwise the other answers should be able to help you. You might also want to look into the * operator ("unpacks" a list, so e.g. [*l,(4,5)] == [(1,2),(2,3),(3,4),(4,5)]) as well.
Either way, you might want to improve your phrasing for any other question you intend to post. Give concrete examples of what you want, what you tried and what (unintended) effects that had.

Count elements in a nested list in an elegant way

I have nested tuples in a list like
l = [(1, 'a', 'b'), (2, 'b', 'c'), (3, 'e', 'a')]
I want to know how many 'a' and 'b' in the list in total. So I currently use the following code to get the result.
amount_a_and_b = len([None for _, elem2, elem3 in l if elem2 == 'a' or elem3 == 'b'])
But I got amount_a_and_b = 1, so how to get the right answer?
Also, is there a more elegant way (less code or higher performance or using builtins) to do this?
I'd flatten the list with itertools.chain.from_iterable() and pass it to a collections.Counter() object:
from collections import Counter
from itertools import chain
counts = Counter(chain.from_iterable(l))
amount_a_and_b = counts['a'] + counts['b']
Or use sum() to count how many times a value appears in the flattened sequence:
from itertools import chain
amount_a_and_b = sum(1 for v in chain.from_iterable(l) if v in {'a', 'b'})
The two approaches are pretty much comparable in speed on Python 3.5.1 on my Macbook Pro (OS X 10.11):
>>> from timeit import timeit
>>> from collections import Counter
>>> from itertools import chain
>>> l = [(1, 'a', 'b'), (2, 'b', 'c'), (3, 'e', 'a')] * 1000 # make it interesting
>>> def counter():
... counts = Counter(chain.from_iterable(l))
... counts['a'] + counts['b']
...
>>> def summing():
... sum(1 for v in chain.from_iterable(l) if v in {'a', 'b'})
...
>>> timeit(counter, number=1000)
0.5640139860006457
>>> timeit(summing, number=1000)
0.6066895100011607
You want to avoid putting data in a datastructure. The [...] syntax constructs a new list and fills it with the content you put in ... , after which the length of the array is taken and the array is never used. If the list if very large, this uses a lot of memory, and it is inelegant in general. You can also use iterators to loop over the existing data structure, e.g., like so:
sum(sum(c in ('a', 'b') for c in t) for t in l)
The c in ('a', 'b') predicate is a bool which evaluates to a 0 or 1 when cast to an int, causing the sum() to only count the tuple entry if the predicate evaluates to True.
Just for fun, functional method using reduce:
>>> l = [(1, 'a', 'b'), (2, 'b', 'c'), (3, 'e', 'a')]
>>> from functools import reduce
>>> reduce(lambda x, y: (1 if 'a' in y else 0) + (1 if 'b' in y else 0) + x, l, 0)
4
You can iterate over both the list and the sub-lists in one list comprehension:
len([i for sub_list in l for i in sub_list if i in ("a", "b")])
I think that's fairly concise.
To avoid creating a temporary list, you could use a generator expression to create a sequence of 1s and pass that to sum:
sum(1 for sub_list in l for i in sub_list if i in ("a", "b"))
Although this question already has an accepted answer, just wondering why all of them as so complex. I would think that this would suffice.
>>> l = [(1, 'a', 'b'), (2, 'b', 'c'), (3, 'e', 'a')]
>>> total = sum(tup.count('a') + tup.count('b') for tup in l)
>>> total
4
Or
>>> total = sum(1 for tup in l for v in tup if v in {'a', 'b'})

match the pattern at the end of a string?

Imagine I have the following strings:
['a','b','c_L1', 'c_L2', 'c_L3', 'd', 'e', 'e_L1', 'e_L2']
Where the "c" string has important sub-categories (L1, L2, L3). These indicate special data for our purposes that have been generated in a program based a pre-designated string "L". In other words, I know that the special entries should have the form:
name_Lnumber
Knowing that I'm looking for this pattern, and that I am using "L" or more specifically "_L" as my designation of these objects, how could I return a list of entries that meet this condition? In this case:
['c', 'e']
Use a simple filter:
>>> l = ['a','b','c_L1', 'c_L2', 'c_L3', 'd', 'e', 'e_L1', 'e_L2']
>>> filter(lambda x: "_L" in x, l)
['c_L1', 'c_L2', 'c_L3', 'e_L1', 'e_L2']
Alternatively, use a list comprehension
>>> [s for s in l if "_L" in s]
['c_L1', 'c_L2', 'c_L3', 'e_L1', 'e_L2']
Since you need the prefix only, you can just split it:
>>> set(s.split("_")[0] for s in l if "_L" in s)
set(['c', 'e'])
you can use the following list comprehension :
>>> set(i.split('_')[0] for i in l if '_L' in i)
set(['c', 'e'])
Or if you want to match the elements that ends with _L(digit) and not something like _Lm you can use regex :
>>> import re
>>> set(i.split('_')[0] for i in l if re.match(r'.*?_L\d$',i))
set(['c', 'e'])

Converting the output of itertools.permutations from list of tuples to list of strings

Having some issues with a list after using the itertools permutations function.
from itertools import permutations
def longestWord(letters):
combinations = list(permutations(letters))
for s in combinations:
''.join(s)
print(combinations)
longestWord("aah")
The output looks like this:
[('a', 'a', 'h'), ('a', 'h', 'a'), ('a', 'a', 'h'), ('a', 'h', 'a'),
('h', 'a', 'a'), ('h', 'a', 'a')]
I would like this to be a simple list, but it seems to be coming out as a list of tuples(?). Can anyone help me format this so it comes out as the following:
['aah', 'aha', 'aah', 'aha', 'haa', 'haa']
from itertools import permutations
def longestWord(letters):
return [''.join(i) for i in permutations(letters)]
print(longestWord("aah"))
Result:
['aah', 'aha', 'aah', 'aha', 'haa', 'haa']
A few suggestions:
Don't print inside the function, return instead and print the returned value.
Your naming of variable combination is not good, as combination is different from permutation
Your join wasn't doing anything, join doesn't change value inline, it returns the string
The function name does not represent what it does. longest word?
Permutations returns an iterator yielding tuples so you need to join them. A map is a nice way to do it instead of your for-loop.
from itertools import permutations
def longestWord(letters):
combinations = list(map("".join, permutations(letters)))
print(combinations)
longestWord("aah")
The way you were doing it, you were joining the letters in each tuple into a single string but you weren't altering the combinations list.
one liner
[''.join(h) for h in [list(k) for k in longestWord("aah")]]
Try this instead:
combinations = permutations(letters)
print [''.join(x) for x in combinations]
(Your join wasn't really doing anything useful--after the join was performed its return value wasn't saved.)

Categories