Remove odd-indexed elements from list in Python - python

I'm trying to remove the odd-indexed elements from my list (where zero is considered even) but removing them this way won't work because it throws off the index values.
lst = ['712490959', '2', '623726061', '2', '552157404', '2', '1285252944', '2', '1130181076', '2', '552157404', '3', '545600725', '0']
def remove_odd_elements(lst):
i=0
for element in lst:
if i % 2 == 0:
pass
else:
lst.remove(element)
i = i + 1
How can I iterate over my list and cleanly remove those odd-indexed elements?

You can delete all odd items in one go using a slice:
del lst[1::2]
Demo:
>>> lst = ['712490959', '2', '623726061', '2', '552157404', '2', '1285252944', '2', '1130181076', '2', '552157404', '3', '545600725', '0']
>>> del lst[1::2]
>>> lst
['712490959', '623726061', '552157404', '1285252944', '1130181076', '552157404', '545600725']
You cannot delete elements from a list while you iterate over it, because the list iterator doesn't adjust as you delete items. See Loop "Forgets" to Remove Some Items what happens when you try.
An alternative would be to build a new list object to replace the old, using a list comprehension with enumerate() providing the indices:
lst = [v for i, v in enumerate(lst) if i % 2 == 0]
This keeps the even elements, rather than remove the odd elements.

Since you want to eliminate odd items and keep the even ones , you can use a filter as follows :
>>>filtered_lst=list(filter(lambda x : x % 2 ==0 , lst))
this approach has the overhead of creating a new list.

Related

Split array based on value

I have an array:
foo = ['1', '2', '', '1', '2', '3', '', '1', '', '2']
¿Is there any efficient way to split this array into sub-arrays using '' as separator?
I want to get:
foo = [['1', '2'], ['1', '2', '3'], ['1'], ['2']]
In one line:
[list(g) for k, g in itertools.groupby(foo, lambda x: x == '') if not k]
Edit:
From the oficial documentation:
groupby
generates a break or new group every time the value of the key
function changes (which is why it is usually necessary to have sorted
the data using the same key function).
The key I generate can be True, or False. It changes each time we find the empty string element. So when it's True, g will contain an iterable with all the element before finding an empty string. So I convert this iterable as a list, and of course I add the group only when the key change
Don't know how to explain it better, sorry :/ Hope it helped
Create a list containing a single list.
output = [[]]
Now, iterate over your input list. If the item is not '', append it to the last element of output. If it is, add an empty list to output.
for item in foo:
if item == '':
output.append([])
else:
output[-1].append(item)
At the end of this, you have your desired output
[['1', '2'], ['1', '2', '3'], ['1'], ['2']]

Python: How to change the data type of every element in every sublist of a list. In this case: int to str

Given a list like list1 = [[1,2,3],[4,5,6]], in order to get back [['1','2','3'],['4','5,'6']], I have tried this:
for i in list1:
for j in i:
j = str(j)
list1
which does nothing to the list: it outputs list1 unchanged. I though it would work by reassigning, something like a[0][0] = str(a[0][0]) (which does work) in a loop. Of course, the for loop above won't do that.
Also tried "map", as in
for i in list1:
for j in i:
list(map(str,i)
which also doesn absolutely nothing to list1.
I am trying to alter the original list, which should be possible. Maybe a new list would be the case, but I'm almost sure it's unnecessary.
Can someone help?
Thank you.
You can try list comprehension
[[str(j) for j in i] for i in list1]
# or
# [list(map(str,i)) for i in list1]
[['1', '2', '3'], ['4', '5', '6']]
Use nested list comperhension
list1 = [[1,2,3],[4,5,6]]
[[str(x) for x in y] for y in list1]
will return
[['1', '2', '3'], ['4', '5', '6']]
Yes, you can use map function somehow like this:
def convert(x=[]):
return [str(i) for i in x]
>>list(map(convert,x))
[['1', '2', '3'], ['4', '5', '6']]
Please check out mutable/immutable objects in Python
for i in list1: # i is a list(mutable)
for j in i: # j is an int(immutable)
j = str(j) # j reference to new string object
int is immutable (not allow changes after creation), so this line
j = str(j)
created a new string object referred by j and the object in list i remains unchanged.
list, dict, set, byte array are mutable objects.
Changing the object value in a list can be done like this:
for i in list1: # i is a list(mutable)
for j in range(len(i)): # this time, j is index of list i
i[j] = str(i[j]) # change the list values
And the result,
list1
[['1', '2', '3'], ['4', '5', '6']]

how to remove the first occurence of an integer in a list

this is my code:
positions = []
for i in lines[2]:
if i not in positions:
positions.append(i)
print (positions)
print (lines[1])
print (lines[2])
the output is:
['1', '2', '3', '4', '5']
['is', 'the', 'time', 'this', 'ends']
['1', '2', '3', '4', '1', '5']
I would want my output of the variable "positions" to be; ['2','3','4','1','5']
so instead of removing the second duplicate from the variable "lines[2]" it should remove the first duplicate.
You can reverse your list, create the positions and then reverse it back as mentioned by #tobias_k in the comment:
lst = ['1', '2', '3', '4', '1', '5']
positions = []
for i in reversed(lst):
if i not in positions:
positions.append(i)
list(reversed(positions))
# ['2', '3', '4', '1', '5']
You'll need to first detect what values are duplicated before you can build positions. Use an itertools.Counter() object to test if a value has been seen more than once:
from itertools import Counter
counts = Counter(lines[2])
positions = []
for i in lines[2]:
counts[i] -= 1
if counts[i] == 0:
# only add if this is the 'last' value
positions.append(i)
This'll work for any number of repetitions of values; only the last value to appear is ever used.
You could also reverse the list, and track what you have already seen with a set, which is faster than testing against the list:
positions = []
seen = set()
for i in reversed(lines[2]):
if i not in seen:
# only add if this is the first time we see the value
positions.append(i)
seen.add(i)
positions = positions[::-1] # reverse the output list
Both approaches require two iterations; the first to create the counts mapping, the second to reverse the output list. Which is faster will depend on the size of lines[2] and the number of duplicates in it, and wether or not you are using Python 3 (where Counter performance was significantly improved).
you can use a dictionary to save the last position of the element and then build a new list with that information
>>> data=['1', '2', '3', '4', '1', '5']
>>> temp={ e:i for i,e in enumerate(data) }
>>> sorted(temp, key=lambda x:temp[x])
['2', '3', '4', '1', '5']
>>>

How to insert an item into a sublist if sublist is a certain length?

If sublist is 4 items, keep, if list is 3 items insert "Null" into the third place of the sublist. A for loop with a conditional "if" would do it, but it's pretty slow. Is there any faster method?
lst = [['4','4','4','4'],['3','3','3'],['1','42','','4'],['1','2','3']]
Desired_List = [['4','4','4','4'],['3','3','Null','3'],['1','42','5','4'],['1','2','Null','3']]
What I have, which doesn't work for some reason I don't understand:
Desired_List = []
for sublist in lst:
if len(sublist) == 3:
Desired_List.extend(sublist.insert(3,"Null"))
else:
Desired_List.extend(sublist)
This is really slow as I'm doing this to a large list. Are there any faster methods?
if you already change lst consider just using it instead of creating a new list Desired_List, simply do:
>>> for sublist in lst:
... if len(sublist) == 3:
... sublist.insert(2,"Null")
...
>>> lst
[['4', '4', '4', '4'], ['3', '3', 'Null', '3'], ['1', '42', '', '4'], ['1', '2', 'Null', '3']]

I have a list of list in python and I want to strip some characters from every two elements

Probably this simle but somehow I am not able to resolve this. I have a list of list from which I want to strip some characters from every two elements and make another list of list
list = [['A*68:02:01:03', 'A*33:01:01', '1'],
['A*68:02:01:02', 'A*33:01:01', '1'],
['A*68:02:01:01', 'A*33:01:01', '1']]
required output = [['A*68:02', 'A*33:01', '1'],
['A*68:02', 'A*33:01', '1'],
['A*68:02', 'A*33:01', '1']]
Finally I want to print only unique elements. Like in the above case all three elements are same so the output should be:
output = ['A*68:02', 'A*33:01', '1']
Thanks for the help
>>> lst = [['A*68:02:01:03', 'A*33:01:01', '1'], ['A*68:02:01:02', 'A*33:01:01', '1'], ['A*68:02:01:01', 'A*33:01:01', '1']]
>>> newLst = [tuple(':'.join(data.split(':', 2)[:2]) for data in sublist) for sublist in lst]
>>> set(newLst)
{('A*68:02', 'A*33:01', '1')}
The interesting bit is the ':'.join(data.split(':', 2)[:2]. The will split data by colons, take only the first two parts and join them again. That way, we strip everything off after the second colon (including that).
The rest is just a list comprehension to go through the nested list. We also need to convert the inner list to a tuple, so they are hashable when we call set() on it. Doing that will get rid of all duplicates.
I think you want:
lst = [['A*68:02:01:03', 'A*33:01:01', '1'],
['A*68:02:01:02', 'A*33:01:01', '1'],
['A*68:02:01:01', 'A*33:01:01', '1']]
output = []
for item in lst:
processed = [":".join(s.split(":")[:2]) for s in item]
if processed not in output:
output.append(processed)
Note: don't call your own variables things like list.
You could do something like this:
def prefix(string):
"""
Returns the prefix of a string, including all characters
up until the second colon.
"""
return ":".join(string.split(":", 2)[:2])
def unique(iterable):
"""
Returns the unique elements in iterable, maintaining the
elements' relative order.
"""
result = []
seen = set()
for el in iterable:
if el not in seen:
seen.add(el)
result.append(el)
return result
L = [
['A*68:02:01:03', 'A*33:01:01', '1'],
['A*68:02:01:02', 'A*33:01:01', '1'],
['A*68:02:01:01', 'A*33:01:01', '1'],
]
prefixes = [(prefix(el[0]), prefix(el[1]), el[2]) for el in L]
# The built-in class set accepts an iterable and returns a set,
# an object with all duplicate elements removed. Since sets are
# unordered, converting the set back to a list will likely
# produce a list in which the original elements have lost their
# relative order.
# If this is a problem you can use the unique function from above.
uniq = list(set(prefixes))
# If you really need a list of lists, instead of a list of tuples.
uniq = [list(el) for el in uniq]
I have renamed your input list to L, because naming it list shadows the built-in function list.

Categories