How to maintain consistency in list? - python

I have a list like
lst = ['a', 'b', 'c', 'd', 'e', 'f']
I have a pop position list
p_list = [0,3]
[lst.pop(i) for i in p_list] changed the list to ['b', 'c', 'd', 'f'], here after 1st iteration list get modified. Next pop worked on the new modified list.
But I want to pop the element from original list at index [0,3] so, my new list should be
['b', 'c', 'e', 'f']

Lots of reasonable answers, here's another perfectly terrible one:
[item for index, item in enumerate(lst) if index not in plist]

You could pop the elements in order from largest index to smallest, like so:
lst = ['a', 'b', 'c', 'd', 'e', 'f']
p_list = [0,3]
p_list.sort()
p_list.reverse()
[lst.pop(i) for i in p_list]
lst
#output: ['b', 'c', 'e', 'f']

Do the pops in reversed order:
>>> lst = ['a', 'b', 'c', 'd', 'e', 'f']
>>> p_list = [0, 3]
>>> [lst.pop(i) for i in reversed(p_list)][::-1]
['a', 'd']
>>> lst
['b', 'c', 'e', 'f']
The important part here is that inside of the list comprehension you should always call lst.pop() on later indices first, so this will only work if p_list is guaranteed to be in ascending order. If that is not the case, use the following instead:
[lst.pop(i) for i in sorted(p_list, reverse=True)]
Note that this method makes it more complicated to get the popped items in the correct order from p_list, if that is important.

Your method of modifying the list may be error prone, why not use numpy to only access the index elements that you want? That way everything stays in place (in case you need it later) and it's a snap to make a new pop list. Starting from your def. of lst and p_list:
from numpy import *
lst = array(lst)
idx = ones(lst.shape,dtype=bool)
idx[p_list] = False
print lst[idx]
Gives ['b' 'c' 'e' 'f'] as expected.

Related

How would you re-order the reordered list back to its previous form?

element = ['a', 'b', 'c', 'd', 'e', 'f', 'g']
index_list = [3,5,6,1,2,4,0]
result = [element[i] for i in index_list]
print(result)
this would eventually give me a ordered list based on the index list which would give
['d', 'f', 'g', 'b', 'c', 'e', 'a'].
How would you re-order this already re-ordered list back to its previous form which would be ['a', 'b', 'c', 'd', 'e', 'f', 'g']? I tried using the given index list again but it did not returned it back, but simply gave me a new list. Would there be any way I could still use the given index list to reorder the list back?
You can do the opposite:
reordered = [None] * len(result)
for index, e in zip(index_list, result):
reordered[index] = e
You can process index_list to do the reverse permutation:
index_list = [3,5,6,1,2,4,0]
reverse = [i for i, n in sorted(enumerate(index_list), key=lambda x: x[1])]
original = [result[i] for i in reverse]
something like this
print([a for a, b in sorted(zip(result, index_list), key=lambda x: x[1])])

How to scan a big list to find if all elements match the ones of a second, smaller, list?

I'm hvaing a hard time with a problem which I thought was pretty simple.
I have two lists:
A small one, that looks like this:
list1 = ['A', 'B', 'C', 'D','E']
The second list is much bigger, going on for about 800 elements. It looks like this:
list2 = ['E', 'B', 'F', 'A', 'C', 'N'...]
I want to scan list2 and see if all of its elements are the same as the ones in list1. If they are different, I want to see which are the elements that differ and cancel them from list2. In this example, I want to print "F" and "N" from list2 and cancel them.
I tried:
found = False
lenght2 = len(list2)
i = 0
for j in list1:
for i in range(0, lenght2):
if i != j:
found = True
#I don't know how to cancel i
print(i)
i = i + 1
break
However, the whole thing does not work.
Is there anyone who could help me?
You could go through all of list2 then check if it is in list one, like this:
for i in range(len(list2)):
if list2[i] in list1:
pass
else:
#Cancel list2[i] ? Or whatever.
Keep it simple:
There's no need to use nested loops here -- you are removing elements from list2, based on information from list1, so loop through list2.
list1 = ['A', 'B', 'C', 'D', 'E']
list2 = ['E', 'B', 'F', 'A', 'C', 'N']
for e in list2[:]:
if e not in list1:
list2.remove(e)
print(list2)
This code loops through list2 and checks for each element (e) if it occurs in list1. If not, it removes it from list2.
Note: the use of list2[:] here rather than list2 is due to this.
Or use a list comprehension:
list1 = ['A', 'B', 'C', 'D', 'E']
list2 = ['E', 'B', 'F', 'A', 'C', 'N']
list2 = [e for e in list2 if e in list1]
print(list2)
See more about how list comprehensions work here.
In both cases, you should get:
['E', 'B', 'A', 'C']

Python: How to generate list with items repeating in two lists

I have two lists of items:
list_1 = ['A', 'B', 'C', 'C', 'D']
list_2 = ['C', 'C', 'F', 'A', 'G', 'D', 'C']
I want to create a new list with the elements that are in the two lists. Like this:
['A', 'C', 'C', 'D']
Notice that it should take in mind that any item can repeat in list several times and should be in the new list as many times as it is repeated in both lists. For instance, 'C' is repeated 2 times in list_1 and 3 times in list_2 so it appears 2 times in the result.
The classic method to do it will be:
import copy
result = []
list_2 = fruit_list_2.copy()
for fruit in fruit_list_1:
if fruit in list_2:
result.append(fruit)
list_2.remove(fruit)
but I am interested to do it by generation lists: [number for number in numbers if number > 0]. Is it possible?
If you aren't terribly concerned about the ordering of the new list, you can use collections.Counter.
>>> list((Counter(list_1) & Counter(list_2)).elements())
['A', 'C', 'C', 'D']
& takes the intersection of the two as multi-sets, with the minimum count used for common elements. The elements method returns the items in the result as an iterator, hence the list wrapper`.
read about collections.Counter
from collections import Counter
list_3 = list((Counter(list_1) & Counter(list_2)).elements())
I think it's as simple as:
list_1 = ['A', 'B', 'C', 'C', 'D']
list_2 = ['C', 'C', 'F', 'A', 'G', 'D', 'C']
list_3 = [x for x in list_1 if x in list_2]
print(list_3)
# returns ['A', 'C', 'C', 'D']
Try this:
[common for common in list_1 if common in list_2]
Happy learning...:)

Index of a list item that occurs multiple times

I have the following code
items = ['a', 'a', 'b', 'a', 'c', 'c', 'd']
for x in items:
print(x, end='')
print(items.index(x), end='')
## out puts: a0a0b2a0c4c4d6
I understand that python finds the first item in the list to index, but is it possible for me to get an output of a0a1b2a3c4c5d6 instead?
It would be optimal for me to keep using the for loop because I will be editing the list.
edit: I made a typo with the c indexes
And in case you really feel like doing it in one line:
EDIT - using .format or format-strings makes this shorter / more legible, as noted in the comments
items = ['a', 'a', 'b', 'a', 'c', 'c', 'd']
print("".join("{}{}".format(e,i) for i,e in enumerate(items)))
For Python 3.7 you can do
items = ['a', 'a', 'b', 'a', 'c', 'c', 'd']
print("".join(f"{e}{i}" for i, e in enumerate(items)))
ORIGINAL
items = ['a', 'a', 'b', 'a', 'c', 'c', 'd']
print("".join((str(e) for item_with_index in enumerate(items) for e in item_with_index[::-1])))
Note that the reversal is needed (item_with_index[::-1]) because you want the items printed before the index but enumerate gives tuples with the index first.
I think you're looking for a0a1b2a3c4c5d6 instead.
for i, x in enumerate(items):
print("{}{}".format(x,i), end='')
Don't add or remove items from your list as you are traversing it. If you want the output specified, you can use enumerate to get the items and the indices of the list.
items = ['a', 'a', 'b', 'a', 'c', 'c', 'd']
for idx, x in enumerate(items):
print("{}{}".format(x, idx), end='')
# outputs a0a1b2a3c4c5d6

search an item of sublist in another list of list by position

I have a list of list created like
biglist=[['A'], ['C', 'T'], ['A', 'T']]
and I will have another list like
smalllist=[['C'], ['T'], ['A', 'T']]
So, I want to check wheter an item in small list contains in that specific index of biglist, if not append to it.
so, making
biglist=[['A','C'], ['C', 'T'], ['A', 'T']]
so, 'C' from fist sublist of smalllist was added to first sublist of biglist. but not for second and third.
I tried like
dd=zip(biglist, smalllist)
for each in dd:
ll=each[0].extend(each[1])
templist.append(list(set(ll)))
but get errors
templist.append(list(set(ll)))
TypeError: 'NoneType' object is not iterable
How to do it?
Thank you
Probably, you should try this:
// This will only work, if smalllist is shorter than biglist
SCRIPT:
biglist = [['A'], ['C', 'T'], ['A', 'T']]
smalllist = [['C'], ['T'], ['A', 'T']]
for i, group in enumerate(smalllist):
for item in group:
if item not in biglist[i]:
biglist[i].append(item)
DEMO:
print(biglist)
# [['A', 'C'], ['C', 'T'], ['A', 'T']]
[list(set(s+b)) for (s,b) in zip(smalllist,biglist)]
For some reason, extend in Python doesn't return the list itself after extending. So ll in your case is None. Just put ll=each[0] on the second line in the loop, and your solution should start working.
Still, I'm not getting, why you don' keep your elements in sets in the first place. This would avoid you from having to convert from list to set and then backwards.
I would just or sets instead of appending to the list and then filtering out duplicates by resorting to set and then to list.
>>> from itertools import izip
>>> templist = []
>>> for els1,els2 in izip(biglist,smalllist):
joined = list(set(els1) | set(els2))
templist.append(joined)
>>> templist
[['A', 'C'], ['C', 'T'], ['A', 'T']]
Keeping elements in sets in the first place seems to be the fastest in Python 3 even for such small amount of elements in each set (see comments):
biglist=[set(['A']), set(['C', 'T']), set(['A', 'T'])]
smalllist=[set(['C']), set(['T']), set(['A', 'T'])]
for els1,els2 in zip(biglist,smalllist):
els1.update(els2)
print(biglist)
Ouput:
[{'A', 'C'}, {'C', 'T'}, {'A', 'T'}]

Categories

Resources