I have an input list as follows:
test_list = ['a', ('abc', 'd'), ['efgh', 'i'], 'jkl']
which I need to flatten, so getting rid of the tuple and list as respective second and third element of test_list
Expected output:
['a', 'abc', 'd', 'efgh', 'i', 'jkl']
I have a problem finding the correct list comprehension for this.
I have tried the following 2 examples:
result = [xs if type(xs) is str else x for xs in test_list for x in xs]
print('result', result)
# this outputs:
# ['a', 'abc', 'd', 'efgh', 'i', 'jkl', 'jkl', 'jkl']
result = [x if ((type(xs) is list) or (type(xs) is tuple)) else xs for xs in test_list for x in xs]
print('result',result)
#this also outputs:
# ['a', 'abc', 'd', 'efgh', 'i', 'jkl', 'jkl', 'jkl']
as you can see, it does "flatten" the list, but it repeats the last element based on the number of characters in the last element. Example if the last element of the test_list is 'jklm' then the in the result the last element is repeated 4 times.
I would like to know if there is a list comprehension which flatten my input list to the expected output without repeating the last element.
The following nested comprehension will work:
[x for sub in test_list for x in (sub if isinstance(sub, (list, tuple)) else [sub])]
This uses isinstance which should preferred over type(...) and can be given multiple types. If any top level element is not a list or tuple, it is wrapped in a list.
You can try:
test_list = ['a', ('abc', 'd'), ['efgh', 'i'], 'jkl']
result = [x for xs in test_list for x in (xs if isinstance(xs, (tuple, list)) else [xs])]
But I wouldn't use this, I would just write a for loop
You could always convert all single elements in test_list to lists:
>>> test_list = ['a', ('abc', 'd'), ['efgh', 'i'], 'jkl']
>>> convert_to_lists = [[x] if not isinstance(x, (list, tuple)) else x for x in test_list]
>>> convert_to_lists
[['a'], ('abc', 'd'), ['efgh', 'i'], ['jkl']]
Then just flatten this with itertools.chain_from_iterable:
>>> from itertools import chain
>>> list(chain.from_iterable(convert_to_lists))
['a', 'abc', 'd', 'efgh', 'i', 'jkl']
or all in one line:
list(chain.from_iterable([x] if not isinstance(x, (list, tuple)) else x for x in test_list))
Using for loop and function for future use.
Added primitives instead of type.
Splitting at , which you can change according to your requirements
list_1 = ['a', ('abc', 'd'), ['efgh', 'i'], 'jkl', {2,2.5}]
def to_flatten(my_list, primitives=(bool, str, int, float)):
flatten = []
my_list = [stuff.split(',') if type(stuff) == str else stuff for stuff in list_1]
for item in my_list:
if isinstance(item, primitives):
flatten.append(item)
else:
flatten.extend(item)
return flatten
print(to_flatten(list_1))
gives
['a', 'abc', 'd', 'efgh', 'i', 'jkl', 2, 2.5]
[Program finished]
you can use join() method
>>> test_list = ['a', ('abc', 'd'), ['efgh', 'i'], 'jkl']
>>> ",".join([",".join(i) if type(i) in [list,tuple] else i for i in test_list]).split(",")
['a', 'abc', 'd', 'efgh', 'i', 'jkl']
>>>
Related
I have a list ['a','b','c','d'], want to make another list, like this: ['a', 'ab', abc', 'abcd']?
Thanks
Tried:
list1=['a','b','c', 'd']
for i in range(1, (len(list1)+1)):
for j in range(1, 1+i):
print(*[list1[j-1]], end = "")
print()
returns:
a
ab
abc
abcd
It does print what i want, but not sure,how to add it to a list to look like ['a', 'ab', abc', 'abcd']
Use itertools.accumulate, which by default sums up the elements for accumulation like a cummulative sum. Since addition (__add__) is defined for str and results in the concatenation of the strings
assert "a" + "b" == "ab"
we can use accumulate as is:
import itertools
list1 = ["a", "b", "c", "d"]
list2 = list(itertools.accumulate(list1)) # list() because accumulate returns an iterator
print(list2) # ['a', 'ab', 'abc', 'abcd']
Append to a second list in a loop:
list1=['a','b','c', 'd']
list2 = []
s = ''
for c in list1:
s += c
list2.append(s)
print(list2)
Output:
['a', 'ab', 'abc', 'abcd']
list1=['a','b','c', 'd']
l = []
for i in range(len(list1)):
l.append("".join(list1[:i+1]))
print(l)
Printing stuff is useless if you want to do ANYTHING else with the data you are printing. Only use it when you actually want to display something to console.
You could form a string and slice it in a list comprehension:
s = ''.join(['a', 'b', 'c', 'd'])
out = [s[:i+1] for i, _ in enumerate(s)]
print(out):
['a', 'ab', 'abc', 'abcd']
You can do this in a list comprehension:
vals = ['a', 'b', 'c', 'd']
res = [''.join(vals[:i+1]) for i, _ in enumerate(vals)]
Code:
[''.join(list1[:i+1]) for i,l in enumerate(list1)]
Output:
['a', 'ab', 'abc', 'abcd']
a='sadfaad'
b=[]
b.append(x for x in a)
print(b)
It returns
[<generator object <genexpr> at 0x000002042A1DA5F0>]
What to know why it happens so? and how can we use list comprehension for it?
To get the actual result of the comprehension, you need to exhaust the generator by converting to list:
a='sadfaad'
b=[]
b.append([x for x in a])
print(b)
output: [['s', 'a', 'd', 'f', 'a', 'a', 'd']]
If you want to add the elements, use extend:
a='sadfaad'
b=[]
b.extend([x for x in a])
print(b)
output: ['s', 'a', 'd', 'f', 'a', 'a', 'd']
But, unless this is just a toy example, the best remains to convert without loop:
b = list(a)
print(b)
output: ['s', 'a', 'd', 'f', 'a', 'a', 'd']
You can also do a simple list comprehension like this:
a='sadfaad'
b = [x for x in a]
And that will return a list of characters in a
(x for x in a) # This will produce a generator that will yield x when called. Note '()' syntax
[x for x in a] # This will produce a list. Note the '[]' syntax
In fact, [x for x in a] can be thought of as a generator expression wrapped in a list constructor.
[x for x in a] is really the same as list(x for x in a)
how do I convert all the numerical strings, inside a list of list that contains both alphabetical, and numerical strings, into an integer?
My Output:
[['69', ' Test', 'Results'], ['A', 'B', 'C'], ['D', '420', 'F']]
Intended Output:
[[69, ' Test', 'Results'], ['A', 'B', 'C'], ['D', 420, 'F']]
Note that my code reads a CSV file. Thanks everyone
def get_csv_as_table(a, b):
s = False
import csv
with open(a) as csv_file:
file_reader = csv.reader(csv_file, delimiter=b)
member = list(file_reader)
print(member)
print ("Enter filename: ")
a = input()
print ("Enter the delimiter: ")
b = input()
get_csv_as_table(a, b)
You can use list comprehension to achieve this. The only minor downside to this is that you will be creating a new list for this instead of modifying the existing list.
my_list = [['69', 'Test', 'Results'], ['A', 'B', 'C'], ['D', '420', 'F']]
filtered_list = [
[int(item) if item.isdigit() else item for item in sub_list]
for sub_list in my_list
]
If you want to edit the list in-place, you can use traditional for-loop. The following code will edit the existing list without creating a new list. This could turn out to be useful in case you have a large list.
my_list = [['69', 'Test', 'Results'], ['A', 'B', 'C'], ['D', '420', 'F']]
for i in range(len(my_list)):
for j in range(len(my_list[i])):
if my_list[i][j].isdigit():
my_list[i][j] = int(my_list[i][j])
str.isdigit() checks if a given string is a number or not. An important note to keep in mind is that, it does not work for floating-point numbers, just integers. Once the condition passes, the item is converted to integer.
Yoy have to combine 2 levels of list-comprehension and use str.isdigit()
values = [
[int(val) if val.isdigit() else val for val in row]
for row in values
]
Try with 2-level list comprehension and int()+.isdigit() power combo in list comprehension ;-)
l=[['69', ' Test', 'Results'], ['A', 'B', 'C'], ['D', '420', 'F']]
l=[[int(y) if y.isdigit() else y for y in x] for x in l]
print(l)
Output:
[[69, ' Test', 'Results'], ['A', 'B', 'C'], ['D', 420, 'F']]
.isdigit() only works on string representation of pure integers, In case if you have floats too then replace '.' to nothing ;-)
l=[['69', ' Test', 'Results'], ['A', 'B', 'C'], ['D', '420', 'F']]
l=[[float(y) if y.replace('.','').isdigit() else y for y in x] for x in l]
print(l)
Output:
[[69.0, ' Test', 'Results'], ['A', 'B', 'C'], ['D', 420.0, 'F']]
I'm new to programming, and I need some help.
I have a list like this
a=[[('the', 'b'), ('hotel', 'i')],[('the', 'b'), ('staff', 'i')]]
and I'm trying to get rid of the tuple while retaining the data in a list, the outcome should look like this
output=[['the', 'b', 'hotel', 'i'],['the', 'b', 'staff', 'i']]
Thank you so much
You can do the following list comprehension:
>>> [[y for x in i for y in x] for i in a]
[['the', 'b', 'hotel', 'i'], ['the', 'b', 'staff', 'i']]
Note that this has nothing to do with tuples, which because of duck typing are treated the exact same way as lists in a list comprehension. You are essentially doing the operation described in Making a flat list out of list of lists in Python over multiple list items.
I guess you can use:
output = []
for x in a:
output.append([element for tupl in x for element in tupl])
outputs:
[['the', 'b', 'hotel', 'i'], ['the', 'b', 'staff', 'i']]
Here is a "functional"-style variant of #nfn neil's A.
from itertools import repeat
list(map(list, map(sum, a, repeat(()))))
# -> [['the', 'b', 'hotel', 'i'], ['the', 'b', 'staff', 'i']]
This can be accomplished via the sum function:
a=[[('the', 'b'), ('hotel', 'i')],[('the', 'b'), ('staff', 'i')]]
output = [sum(elem, ()) for elem in a]
print(output)
And if it must return a list:
a=[[('the', 'b'), ('hotel', 'i')],[('the', 'b'), ('staff', 'i')]]
output = [sum(map(list,elem), []) for elem in a]
print(output)
I have a list of strings like
['ABC', 'DEF', 'GHIJ']
and I want a list of strings containing the first letter of each string, i.e.
['A', 'D', 'G'].
I thought about doing that using map and the function that returns the first element of a list: my_list[0]. But how can I pass this to map?
Thanks.
you can try
In [14]: l = ['ABC', 'DEF', 'GHIJ']
In [15]: [x[0] for x in l]
Out[15]: ['A', 'D', 'G']
You should use a list comprehension, like #avasal since it's more pythonic, but here's how to do it with map:
>>> from operator import itemgetter
>>> L = ['ABC', 'DEF', 'GHIJ']
>>> map(itemgetter(0), L)
['A', 'D', 'G']
use list comprehension like so:
results = [i[0] for i in mySrcList]
One way:
l1=['ABC', 'DEF', 'GHIJ']
l1=map(lambda x:x[0], l1)
a=['ABC','DEF','GHI']
b=[]
for i in a:
b.append(i[0])
b is the array you need.
Try this.
>>> myArray=['ABC', 'DEF', 'GHIJ']
>>> newArray=[]
>>> for i in map(lambda x:x[0],myArray):
... newArray.append(i)
...
>>> print(newArray)
['A', 'D', 'G']