Remove First occurance of an element from list python - python

I have two lists:
List_main = ['a','b','c','d','e','f','g','h']
List_sub = ['c','f','d']
I now joined these lists into:
list_joined = ['a','b','c','d','e','f','g','h','c','f','d']
I want to remove the first occurrences of elements in List_sub from the joined list 'list_joined'.
Final output i am looking for is to obtain a list which has the List_sub elements appended at the end.:
['a','b','e','g','h','c','f','d']
I tried an approach where i found out the index of sub_list elements from the List_main.
[i for i,x in enumerate(path_stores_new) if x == value ]
and then use
del list_joined[index]
But i think there may be a better way of doing this.
Any leads?
Note: List_main has unique values

Can be done easily using a list comprehension
a one liner for this is as in the code below:
List_main = ['a','b','c','d','e','f','g','h']
List_sub = ['c','f','d']
list_joined = [i for i in List_main if i not in List_sub] + List_sub
EDIT:
The above code ignored all the occurrences if only the first occurrence is to be ignored the code below should do the job.
List_main = ['a','b','c','d','e','f','g','h']
List_sub = ['c','f','d']
list_joined = [value for ind, value in enumerate(List_main) if value not in List_sub or ind > List_main.index(value)] + List_sub

Alternatively, you can also use the built-in filter function like this:
List_main = ['a','b','c','d','e','f','g','h']
List_sub = ['c','f','d']
sub_filter = lambda x: x not in List_sub
list_joined = list(filter(sub_filter, List_main)) + List_sub
This will output ['a', 'b', 'e', 'g', 'h', 'c', 'f', 'd'].

I wouldn't do exactly the same as #Rakesh, I'm just sending what I would have done even though our answers are very very similar. :)
arr = [1, 2, 3, 4, 5]
arr_2 = [2, 3]
for elem in arr_2:
if elem in arr:
arr.remove(elem)
arr += arr_2
print(arr)
# [1, 4, 5, 2, 3]

You can filter elements of first list witch not in the second, and then extend the result with the second list :
List_main = ['a','b','c','d','e','f','g','h']
List_sub = ['c','f','d']
list(filter(lambda x : x not in List_sub, List_main)) + List_sub
Output :
['a', 'b', 'e', 'g', 'h', 'c', 'f', 'd']

try this:
from itertools import filterfalse
def f(x):
if x in List_sub:
List_sub.remove(x)
return True
return False
list(filterfalse(f, list_joined))

You can convert List_main to a dict first, delete the keys based on List_sub, and then join the remaining keys with List_sub, so that the removal of each element in List_sub can be done in an average time complexity of O(1) (otherwise element lookup and removal in list and would cost an average of O(n) per element):
dict_main = dict.fromkeys(List_main)
for k in List_sub:
del dict_main[k]
print(list(dict_main) + List_sub)
This outputs:
['a', 'b', 'e', 'g', 'h', 'c', 'f', 'd']
If you aren't using Python 3.7 you can use collections.OrderedDict instead of dict.

Do something like this, if you want to ignore the first occurrence:
List_main = ['a','b','c','d','e','f','g','h']
List_sub = ['c','f','d']
dict_main = dict.fromkeys(List_sub)
list_joined = []
for x in List_main:
if x in dict_main.keys():
if dict_main[x] is None:
dict_main[x] = 1
else:
list_joined += x
else:
list_joined += x
list_joined += List_sub
print(list_joined)

You can remove it using this code:
list_main = ['a','b','c','d','e','f','g','h']
list_sub = ['c','f','d']
for sub_item in list_sub:
if sub_item in list_main:
list_main.remove(sub_item)
list_main += sub_item
Or just not add a duplicated items:
list_main = ['a','b','c','d','e','f','g','h']
list_sub = ['c','f','d']
for sub_item in list_sub:
if sub_item not in list_main:
list_main.append(sub_item)
Also if you don't want to have duplicated items you can use set. But be careful, set doesn't keep your initial order of elements.
list_main = ['a','b','c','d','e','f','g','h']
list_sub = ['c','f','d']
result_list = list(set(list_main + list_sub))

Related

Remove duplicates in nested list with specified index

I want to remove the list which contains the maximum number( In this list 16)
Code sample
Lst = [["D",16],["B",10],["A",13],["B",16]]
required output
Lst =[["B",10],["A",13]]
You can use max to get the maximum number and then filter the original list by using list comprehension:
lst = [["D",16],["B",10],["A",13],["B",16]]
max_num = max(x[1] for x in lst)
output = [sublst for sublst in lst if sublst[1] < max_num]
print(output) # [['B', 10], ['A', 13]]
Lst = [["D",16],["B",10],["A",13],["B",16]]
max_elem = -float("inf")
for element in Lst:
if element[1] > max_elem:
max_elem = element[1]
for i in reversed(range(len(Lst))):
if Lst[i][1] == max_elem:
Lst.pop(i)
print(Lst)

Filter a list by omitting values by indexes

I did not find an easy way to filter a list excluding values by their indexes. For example, I have:
varList = ['r', 2, ('c'), ['e'], 'etc.', { 'su': 'lt'}]
indexList = [1, 2, 4]
and I need to have:
expected = ['r', ['e'], {'su': 'lt'}]
The idiomatic way would be:
[x for i, x in enumerate(varList) if i not in indexList]
which is O(m * n) for m = len(varList) and n = len(indexList). While that is okay for short exclusion lists, for some significant speedup with longer lists you may want to say instead:
indexset = set(indexList)
[x for i, x in enumerate(varList) if i not in indexset]
Which is O(m) only (plus O(n) to make the set).
The easiest way to do this would be using list comprehension:
[value for index,value in enumerate(varList) if index not in indexList]
An in-place solution:
for i in indexList[::-1]:
del varList[i]
Assuming the list of indexes is ascending.
It is necessary to loop from the end to keep the indexes true (if we start by deleting index 1, the element in index 2 will move to index 1 and then we will delete the wrong element). For a more general solution use sorted(indexList, reverse=True).
One of the solution is as the following with the options to omit and to extract:
def getFilteredListByIndexes(
varList: list, indexList: list, mode: str = 'omit') -> list:
""" #Function to filter varlist by indexList
#Args:
varList: list or tuple of any type
indexList: list of tuple of integers
mode: str, that could be 'omit' or 'extract'
"""
resTuple = ()
res = []
if mode == 'omit':
resTuple = list(filter(lambda x: not x[0] in indexList, enumerate(varList)))
elif mode == 'extract':
resTuple = list(filter(lambda x: x[0] in indexList, enumerate(varList)))
else:
resTuple = varList.emumerate()
res = list(map(lambda x: x[1], resTuple))
return res
Usage:
varList = ['r', 2, ('c'), ['e'], 'etc.', { 'su': 'lt'}]
indexList = [1, 2, 4]
expected = ['r', ['e'], {'su': 'lt'}]
res = getFilteredListByIndexes(varList, indexList, 'omit')
print(res) # ['r', ['e'], {'su': 'lt'}]

How to delete repeat elements in this list?

I have a list is a = ['R','R','R','B','R','B','B','S','S']. my goal is to delete repeat 'R's and 'S's and then delete the 'B's (if there is only one R or S, just keep it). Therefore, I want the output to be ['R','R','S'], but mine is ['R', 'S'].
Can anyone help me take look my code? Thank you
This is my code
a = ['R','R','R','B','R','B','B','S','S'] # create a list to store R S B
a = [x for x in a if x != 'B'] # Delete all the B's
new_list = [] # create another list to store R and S without repeat
last = None
for x in a:
if last == x and (len(new_list) == 0 or new_list[-1] != x):
new_list.append(last)
last = x
print(new_list)
My output is this
['R', 'S']
but I want this
['R','R','S']
You could use itertools.groupby to group the elements first, then delete the B values:
from itertools import groupby
a = ['R','R','R','B','R','B','S','S'] # create a list to store R S B
[k for k, v in groupby(a) if k != 'B']
Result:
['R', 'R', 'S']
You could try this. This creates a new list without anything that is a repeat, and no 'B's.
a = ['R','R','R','B','R','B','B','S','S']
new_list = [] # create another list to store R and S without repeat
last = None
for x in a:
if last != x and x!='B':
new_list.append(x)
last = x
print(new_list)
Another option is to use a list comprehension:
a = ['R','R','R','B','R','B','B','S','S']
new_list = [ x for i,x in enumerate(a) if (a[i-1] != x and x!='B') or (i==0) ]
print(new_list)
Output from either example is the same:
['R', 'R', 'S']
Neither of these options require an import. However, I think the groupby code given by Mark Meyer is what I'd use in most cases.
You can use fromkeys in this case.
mylist = ["a", "b", "a", "c", "c"]
mylist = list(dict.fromkeys(mylist))
print(mylist) # ['a', 'b', 'c']

How to count items in list recursively

I am looking to count the items in a list recursively. For example, I have a list few lists:
a = ['b', 'c', 'h']
b = ['d']
c = ['e', 'f']
h = []
I was trying to find a way in which I find out the length of list 'a'. But in list 'a' I have 'b', 'c' and 'h' ... hence my function then goes into list 'b' and counts the number of elements there... Then list 'c' and then finally list 'h'.
b = ['d']
c = ['e', 'f']
h = []
a = [b,c,h]
def recur(l):
if not l: # keep going until list is empty
return 0
else:
return recur(l[1:]) + len(l[0]) # add length of list element 0 and move to next element
In [8]: recur(a)
Out[8]: 3
Added print to help understand the output:
def recur(l,call=1):
if not l:
return 0
else:
print("l = {} and l[0] = {} on recursive call {}".format(l,l[0],call))
call+=1
return recur(l[1:],call) + len(l[0])
If you want to get more deeply nested lists you can flatten and get the len():
b = ['d']
c = ['e', 'f',['x', 'y'],["x"]]
h = []
a = [b,c,h]
from collections import Iterable
def flatten_nest(l):
if not l:
return l
if isinstance(l[0], Iterable) and not isinstance(l[0],basestring): # isinstance(l[0],str) <- python 3
return flatten_nest(l[0]) + flatten_nest(l[1:])
return l[:1] + flatten_nest(l[1:])
In [13]: len(flatten_nest(a))
Out[13]: 6
The solution that worked for me was this:
def recur(arr):
if not arr:
return 0
else:
return 1 + recur(arr[1:])

Python: Append double items to new array

lets say I have an array "array_1" with these items:
A b A c
I want to get a new array "array_2" which looks like this:
b A c A
I tried this:
array_1 = ['A','b','A','c' ]
array_2 = []
for item in array_1:
if array_1[array_1.index(item)] == array_1[array_1.index(item)].upper():
array_2.append(array_1[array_1.index(item)+1]+array_1[array_1.index(item)])
The problem: The result looks like this:
b A b A
Does anyone know how to fix this? This would be really great!
Thanks, Nico.
It's because you have 2 'A' in your array. In both case for the 'A',
array_1[array_1.index(item)+1
will equal 'b' because the index method return the first index of 'A'.
To correct this behavior; i suggest to use an integer you increment for each item. In that cas you'll retrieve the n-th item of the array and your program wont return twice the same 'A'.
Responding to your comment, let's take back your code and add the integer:
array_1 = ['A','b','A','c' ]
array_2 = []
i = 0
for item in array_1:
if array_1[i] == array_1[i].upper():
array_2.append(array_1[i+1]+array_1[i])
i = i + 1
In that case, it works but be careful, you need to add an if statement in the case the last item of your array is an 'A' for example => array_1[i+1] won't exist.
I think that simple flat list is the wrong data structure for the job if each lower case letter is paired with the consecutive upper case letter. If would turn it into a list of two-tuples i.e.:
['A', 'b', 'A', 'c'] becomes [('A', 'b'), ('A', 'c')]
Then if you are looping through the items in the list:
for item in list:
print(item[0]) # prints 'A'
print(item[1]) # prints 'b' (for first item)
To do this:
input_list = ['A', 'b', 'A', 'c']
output_list = []
i = 0;
while i < len(input_list):
output_list.append((input_list[i], input_list[i+1]))
i = i + 2;
Then you can swap the order of the upper case letters and the lower case letters really easily using a list comprehension:
swapped = [(item[1], item[0]) for item in list)]
Edit:
As you might have more than one lower case letter for each upper case letter you could use a list for each group, and then have a list of these groups.
def group_items(input_list):
output_list = []
current_group = []
while not empty(input_list):
current_item = input_list.pop(0)
if current_item == current_item.upper():
# Upper case letter, so start a new group
output_list.append(current_group)
current_group = []
current_group.append(current_item)
Then you can reverse each of the internal lists really easily:
[reversed(group) for group in group_items(input_list)]
According to your last comment, you can get what you want using this
array_1 = "SMITH Mike SMITH Judy".split()
surnames = array_1[1::2]
names = array_1[0::2]
print array_1
array_1[0::2] = surnames
array_1[1::2] = names
print array_1
You get:
['SMITH', 'Mike', 'SMITH', 'Judy']
['Mike', 'SMITH', 'Judy', 'SMITH']
If I understood your question correctly, then you can do this:
It will work for any length of array.
array_1 = ['A','b','A','c' ]
array_2 = []
for index,itm in enumerate(array_1):
if index % 2 == 0:
array_2.append(array_1[index+1])
array_2.append(array_1[index])
print array_2
Output:
['b', 'A', 'c', 'A']

Categories

Resources