Is there a Pythonic way for concatenating a list of lists, excluding an index of choice? For example, if I had
[['a'], ['b', 'c'], ['d'], ['e', 'f', 'g']]
and did not want index 1 in the result, my concatenated list would look like:
['a', 'd', 'e', 'f', 'g']
I could do this with a loop and checking against the iteration against my index of choice, but I'm hoping there's a cleaner way.
You can use slicing:
from itertools import chain
ls = [['a'], ['b', 'c'], ['d'], ['e', 'f', 'g']]
list(chain.from_iterable(ls[:1] + ls[2:]))
If you want to avoid the cost of adding the slices together and creating new lists, it gets a bit more complicated:
from itertools import chain, islice
list(chain.from_iterable(chain(islice(ls, 1), islice(ls, 2, None))))
Here is one way:
lists = [['a'], ['b', 'c'], ['d'], ['e', 'f', 'g']]
subset = [x for ind, x in enumerate(lists) if ind != 1]
subset # [['a'], ['d'], ['e', 'f', 'g']]
flattened = [item for l in subset for item in l]
flattened # ['a', 'd', 'e', 'f', 'g']
You could combine these into a single comprehension, I did it in two steps here to show more clearly what each part does.
this is ~ "I could do this with a loop and checking against the iteration against my index of choice...."
but in a list comprehension, no libs
nix = 1
myls = [['a'], ['b', 'c'], ['d'], ['e', 'f', 'g']]
[e for ls in myls for e in ls if ls != myls[nix]]
Out[11]: ['a', 'd', 'e', 'f', 'g']
no need for enumerate either
another of the slice and flatten possibilities that reads nice
sum(myls[:nix] + myls[nix+1:],[])
but some have a problem with the use of sum that way https://mathieularose.com/how-not-to-flatten-a-list-of-lists-in-python/
If you don't mind using an external library I could offer remove and flatten from iteration_utilities1:
>>> from iteration_utilities import remove, flatten
>>> l = [['a'], ['b', 'c'], ['d'], ['e', 'f', 'g']]
>>> list(flatten(remove(l, 1)))
['a', 'd', 'e', 'f', 'g']
1 I'm the author of that library.
Related
given a nested list:
input_list = [['c', 'd'], ['e', 'f']]
addition_to_input_list = ['a', 'b']
required_output = [['a', 'b'], ['c', 'd'], ['e', 'f']]
for my current program, it is enough to put the addition at the start, in the future I may have to also put the addition at a specific index in the nested list.
Thanks in advance
This is a simple list insertion. It doesn't matter that the elements are lists themselves. So, this will do it:
input_list.insert( 0, addition_to_input_list )
Or you can build a new list:
required_output = [addition_to_input_list] + input_list
Proof that both options work:
>>> input_list = [['c', 'd'], ['e', 'f']]
>>> addition_to_input_list = ['a', 'b']
>>> input_list.insert(0,addition_to_input_list)
>>> input_list
[['a', 'b'], ['c', 'd'], ['e', 'f']]
>>> input_list = [['c', 'd'], ['e', 'f']]
>>> [addition_to_input_list]+input_list
[['a', 'b'], ['c', 'd'], ['e', 'f']]
>>>
I want to reorder my list in a given order,
For example I have a list of ['a', 'b', 'c', 'd', 'e', 'f', 'g']
this has an index of [0,1,2,3,4,5,6] and lets say the new ordered list would have an order of [3,5,6,1,2,4,0] which would result in ['d','f','g', 'b', 'c', 'e', 'a'].
How would you result in such code?
I thought of using for loop by doing the
for i in range(Len(list))
and after that I thought go using append or creating a new list? maybe but I'm not sure if I'm approaching this right.
All you need to do is iterate the list of indexes, and use it to access the list of elements, like this:
elems = ['a', 'b', 'c', 'd', 'e', 'f', 'g']
idx = [3,5,6,1,2,4,0]
result = [elems[i] for i in idx]
print(result)
Output:
['d', 'f', 'g', 'b', 'c', 'e', 'a']
import numpy as np
my_list = ['a', 'b', 'c', 'd', 'e', 'f', 'g']
def my_function(my_list, index):
return np.take(my_list, index)
print(my_function(my_list, [3,5,6,1,2,4,0]))
Output: ['d' 'f' 'g' 'b' 'c' 'e' 'a']
If I have a list of lists, and I want to remove all the items after 'd', and I want to do that based on the index location of 'd' in both lists, how would I do that if the index location of 'd' is different in each list.
Is there a better way than indexing?
ab_list = ['a', 'b', 'c' ,'d','e', 'f'], ['a', 'd', 'e', 'f', 'g']
loc=[]
for i in ab_list:
loc.append(i.index('d'))
print(loc)
# output is [3, 1]
for i in ab_list:
for l in loc:
ab_list_keep=(i[0:l])
print(ab_list_keep)
## output is
#['a', 'b', 'c']
#['a']
#['a', 'd', 'e']
#['a']
The first two lines of the output is what I'd want, but making a list out of the index locations of 'd' doesn't seem to be right.
Python's built in itertools.takewhile method is designed for cases like this one:
import itertools
ab_list = ['a', 'b', 'c' ,'d','e', 'f'],['a', 'd', 'e', 'f', 'g']
print([list(itertools.takewhile(lambda i: i != "d", sublist)) for sublist in ab_list])
output:
[['a', 'b', 'c'], ['a']]
I have a list of lists like so
list=[[a], [b], [c], [d],[e],[f], [a,f], [b,c], [c,e], [b, d,f]]
note that it includes singles and combinations.
What I would like to do is to iterate the list so that a new list of every possible combination of these sub-components is appended to the list of lists if and only if they share at least one common entry.
so the product is as follows
list2=[[a], [b], [c], [d],[e],[f], [a,f], [b,c], [c,e], [b, d,f], **[b,c,e], [a,b,d,f], [b,c,d,f], [b,c,d,e,f], [a,b,c,d,e,f]]**
Note the new part of the list contains the original list of lists
def similar(x):
prev_l = 0
while prev_l != len(x):
to_add = []
prev_l = len(x)
for i in x:
if len(i) == 1:
continue
for j in x:
if len(j) == 1:
continue
if any([_ in j for _ in i]) and not any([set(i+j) == set(_) for _ in x]) and not any([set(i+j) == set(_) for _ in to_add]) and i != j:
to_add.append(list(set(i+j)))
x += to_add
return x
Input:
>>> l = [['a'], ['b'], ['c'], ['d'],['e'],['f'], ['a','f'], ['b','c'], ['c','e'], ['b', 'd','f']]
>>> similar(l)
Output:
>>> l
[['a'], ['b'], ['c'], ['d'], ['e'], ['f'], ['a', 'f'], ['b', 'c'], ['c', 'e'], ['b', 'd', 'f'], ['b', 'a', 'd', 'f'], ['b', 'e', 'c'], ['b', 'd', 'c', 'f'], ['b', 'a', 'f', 'd', 'c'], ['b', 'f', 'e', 'd', 'c'], ['b', 'a', 'f', 'e', 'd', 'c']]
I should note this has O(n^3) in worst case. If you're using this for something floyd warshall I wouldn't be too worried as that has O(n^3) anyway, but if not you should definitely populate a distance matrix and then look for adjacency in that.
I have a list as follows:
l = [['A', 'C', 'D'], ['B', 'E'], ['A', 'C', 'D'], ['A', 'C', 'D'], ['B', 'E'], ['F']]
The result should be:
[['A', 'C', 'D'], ['B', 'E'], ['F']]
The order of elements is also not important.
I tried as:
print list(set(l))
Does numpy has better way
Lists are not a "hashable" type and cannot be members of a set.
Frozen sets can, so we first convert to those (also making the sublists order-insentive), and later convert back to lists.
print map(list, set(map(frozenset, l)))
or if you prefer comprehensions,
print [list(x) for x in {frozenset(x) for x in l}]
I doubt numpy offers any "better" (for some definition of better) way.
This way is IMO the clearest and most pythonic.
The reason lists cannot be part of sets is that they are mutable, so the hash now is different from the hash after they are changed; being in a hash-based set would make for confusing behavior.
#!/usr/bin/python
l1 = [['A', 'C', 'D'], ['B', 'E'], ['A', 'C', 'D'], ['A', 'C', 'D'], ['B', 'E'], ['F']]
l2=[]
for l in l1:
if l not in l2:
l2.append(l)
print l2
OUTPUT
[['A', 'C', 'D'], ['B', 'E'], ['F']]
The easiest and straightforward approach where you don't need to convert a non hashable type to hashable and vice versa (which has a performance impact), is to use itertools.groupby
Off-course, the order won;t be maintained but in any case OP categorically specified that it is not a strict requirement
>>> l = [['A', 'C', 'D'], ['B', 'E'], ['A', 'C', 'D'], ['A', 'C', 'D'], ['B', 'E'], ['F']]
>>> from itertools import groupby
>>> [k for k, g in groupby(sorted(l))]
[['A', 'C', 'D'], ['B', 'E'], ['F']]