Remove list element without mutation - python

Assume you have a list
>>> m = ['a','b','c']
I'd like to make a new list n that has everything except for a given item in m (for example the item 'a'). However, when I use
>>> m.remove('a')
>>> m
m = ['b', 'c']
the original list is mutated (the value 'a' is removed from the original list). Is there a way to get a new list sans-'a' without mutating the original? So I mean that m should still be [ 'a', 'b', 'c' ], and I will get a new list, which has to be [ 'b', 'c' ].

I assume you mean that you want to create a new list without a given element, instead of changing the original list. One way is to use a list comprehension:
m = ['a', 'b', 'c']
n = [x for x in m if x != 'a']
n is now a copy of m, but without the 'a' element.
Another way would of course be to copy the list first
m = ['a', 'b', 'c']
n = m[:]
n.remove('a')
If removing a value by index, it is even simpler
n = m[:index] + m[index+1:]

There is a simple way to do that using built-in function :filter .
Here is ax example:
a = [1, 2, 3, 4]
b = filter(lambda x: x != 3, a)

If the order is unimportant, you can use set (besides, the removal seems to be fast in sets):
list(set(m) - set(['a']))
This will remove duplicate elements from your original list though

We can do it via built-in copy() function for list;
However, should assign a new name for the copy;
m = ['a','b','c']
m_copy=m.copy()
m_copy.remove('a')
print (m)
['a', 'b', 'c']
print(m_copy)
['b', 'c']

You can create a new list without the offending element with a list-comprehension. This will preserve the value of the original list.
l = ['a', 'b', 'c']
[s for s in l if s != 'a']

Another approach to list comprehension is numpy:
>>> import numpy
>>> a = [1, 2, 3, 4]
>>> list(numpy.remove(a, a.index(3)))
[1, 2, 4]

We can do it without using in built remove function and also without creating new list variable
Code:
# List m
m = ['a', 'b', 'c']
# Updated list m, without creating new list variable
m = [x for x in m if x != a]
print(m)
output
>>> ['b', 'c']

The question is useful as I sometimes have a list that I use throughout my given script but I need to at a certain step to apply a logic on a subset of the list elements. In that case I found it useful to use the same list but only exclude the needed element for that individual step, without the need to create a totally new list with a different name. For this you can use either:
list comprehension: say you have l=['a','b','c'] to exclude b, you can have [x for x in l if x!='b']
set [only if order is unimortant]: list(set(l) - set(['b'])), pay attention here that you pass 'b' as list ['b']

Related

find indexes of all None items in a list in python

I have a list of strings, some of them are None.
i want to get a new list of all the Indexes of None.
list = ['a', 'b', None, 'c' ,None, 'd']
using the function index
n = list.index(None)
will only return the first appearance, n= 2, while i want to see n= [2,4].
thanks you.
Try enumerate:
l=[i for i,v in enumerate(list) if v == None]
Or range:
l=[i for i in range(len(list)) if list[i] == None]
Both cases:
print(l)
Is:
[2,4]
Big Note: it is not good to name variables a existing method name, that overwrites it, (now it's list), so i would prefer it as l (or something)
I recommend the first example because enumerate is easy, efficient.
Here's something different but it doesn't use list comprehension:
>>> l = ['a', 'b', None, 'c' ,None, 'd']
>>> out = []
>>> for _ in range(l.count(None)):
out.append(l.index(None))
l[l.index(None)] = "w"
>>> out
[2, 4]
>>>
Faster way. Very useful in case of long list.
list = ['a', 'b', None, 'c' ,None, 'd']
import numpy as np
print(np.where(np.array(list) == None)[0])
Output :
[2 4]
In case you need list of index :
print(np.where(np.array(list) == None)[0].tolist())
>>> [2, 4]

Replace elements in a list of lists python

I have a list of lists as follows:
list=[]
*some code to append elements to list*
list=[['a','bob'],['a','bob'],['a','john']]
I want to go through this list and change all instances of 'bob to 'b' and leave others unchanged.
for x in list:
for a in x:
if "bob" in a:
a.replace("bob", 'b')
After printing out x it is still the same as list, but not as follows:
list=[['a','b'],['a','b'],['a','john']]
Why is the change not being reflected in list?
Because str.replace doesn't work in-place, it returns a copy. As immutable objects, you need to assign the strings to elements in your list of lists.
You can assign directly to your list of lists if you extract indexing integers via enumerate:
L = [['a','bob'],['a','bob'],['a','john']]
for i, x in enumerate(L):
for j, a in enumerate(x):
if 'bob' in a:
L[i][j] = a.replace('bob', 'b')
Result:
[['a', 'b'], ['a', 'b'], ['a', 'john']]
More Pythonic would be to use a list comprehension to create a new list. For example, if only the second of two values contains names which need checking:
L = [[i, j if j != 'bob' else 'b'] for i, j in L]
You can try using a dictionary object of python
import numpy as np
L = [['a','bob'],['a','bob'],['a','john']]
dic = {'bob':'b'} # you can specify more changes here
new_list = [dic.get(n, n) for n in np.concatenate(L)]
print(np.reshape(new_list,[-1,2]).tolist())
Result is
[['a', 'b'], ['a', 'b'], ['a', 'john']]
I'm going to use a simple example, but basically x is another variable and isn't linked to the list element. You have to change the list element directly in order to alter the list.
l=[1,2,3,4]
for x in l:
x=x+1
This doesn't change the list
l=[1,2,3,4]
for i,x in enumerate(l):
l[i]=x+1
this changes the list
I might be a little to the party, but a more Pythonic way of doing this is using a map and a list comprehension. It can operate on a list of the list with any number of values.
l = [['a','bob'],['a','bob'],['a','john']]
[list(map(lambda x: x if x != 'bob' else 'b', i)) for i in l]
it gives you the desired output
[['a', 'b'], ['a', 'b'], ['a', 'john']]
The main idea is that the inner loop is iterating through the inner loop and using the simple lambda function to perform the replacement.
I hope that this helps anyone else who is looking out for something similar.
This is the case because you are only changing the temporary variable a.
list = [1,2,3]
for i in list:
i+=1
list will still be [1,2,3]
you have to edit the string based on its index in the list

Elegant slicing in python list based on index

I was wondering what would be an efficient an elegant way of slicing a python list based on the index. In order to provide a minimal example:
temp = ['a','b','c','d']
index_needed=[0,2]
How can I slice the list without the loop?
expected output
output_list =['a','c']
I have a sense that there would be a way but haven't figured out any. Any suggestions?
First, note that indexing in Python begins at 0. So the indices you need will be [0, 2].
You can then use a list comprehension:
temp = ['a', 'b', 'c', 'd']
idx = [0, 2]
res = [temp[i] for i in idx] # ['a', 'c']
With built-ins, you may find map performs better:
res = map(temp.__getitem__, idx) # ['a', 'c']
Since you are using Python 2.7, this returns a list. For Python 3.x, you would need to pass the map object to list.
If you are looking to avoid a Python-level loop altogether, you may wish to use a 3rd party library such as NumPy:
import numpy as np
temp = np.array(['a', 'b', 'c', 'd'])
res = temp[idx]
# array(['a', 'c'],
# dtype='<U1')
res2 = np.delete(temp, idx)
# array(['b', 'd'],
# dtype='<U1')
This returns a NumPy array, which you can then be converted to a list via res.tolist().
Use this :
temp = ['a','b','c','d']
temp[0:4:2]
#Output
['a', 'c']
Here first value is starting index number which is (Included) second value is ending index number which is (Excluded) and third value is (steps) to be taken.
Happy Learning...:)
An alternative that pushes the work to the C layer on CPython (the reference interpreter):
from operator import itemgetter
temp = ['a','b','c','d']
index_needed=[0,2]
output_list = itemgetter(*index_needed)(temp)
That returns tuple of the values; if list is necessary, just wrap in the list constructor:
output_list = list(itemgetter(*index_needed)(temp))
Note that this only works properly if you need at least two indices; itemgetter is variable return type based on how it's initialized, returning the value directly when it's passed a single key to pull, and a tuple of values when passed more than one key.
It's also not particularly efficient for one-off uses. A more common use case would be if you had an iterable of sequences (typically tuples, but any sequence works), and don't care about them. For example, with an input list of:
allvalues = [(1, 2, 3, 4),
(5, 6, 7, 8)]
if you only wanted the values from index 1 and 3, you could write a loop like:
for _, x, _, y in allvalues:
where you unpack all the values but send the ones you don't care about to _ to indicate the lack of interest, or you can use itemgetter and map to strip them down to what you care about before the unpack:
from future_builtins import map # Because Py2's map is terrible; not needed on Py3
for x, y in map(itemgetter(1, 3), allvalues):
The itemgetter based approach doesn't care if you have more than four items in a given element of allvalues, while manual unpacking would always require exactly four; which is better is largely based on your use case.

convert multiple lists to a dictionary

Is there a way in python to turn a set of lists into a dictionary, where the name of the list is the key and the values are the values? Can you do this with dictionary comprehension?
one = ['a', 'b', 'c']
two = ['d','e','f']
would become
dictionary = {"one" : ['a', 'b', 'c'], "two":['d','e','f'] }
>>> one = ['a', 'b', 'c']
>>> two = ['d','e','f']
>>> c = dict({'one':one, 'two':two})
or
>>> dict(zip(["one", "two"], [one, two]))
Why you want to convert one variable to 'one' and two variable to 'two' is incomprehensible.
I don't think you can necessarily access the variable name, but lets say, if you had a list of those lists, you could set the index of each one as the key value. example:
megaList = [[2, 3, 6], [3, 6, 1]]
dic = {}
for i, l in enumerate(megaList):
dic[i] = l
but in that case you might as well just have the list of lists. Just though I'd share since I'm not sure what you're trying to do, and maybe this can steer you in the right direction.
Or do what #enigma did, if you don't mind typing them out by hand.

How to do this list/dict comprehension in python

I am creating a python dictionary as follows:
d= {i : chr(65+i) for i in range(4)}
Now output of d is {0: 'A', 1: 'B', 2: 'C', 3: 'D'}
I have an list of keys that I want to look up as follows:
l = [0, 1]
Now what I want to do is create another list which contains the values corresponding to these keys and I wanted to know if there was a pythonic way to do so using list or dict comprehensions.
I can do something as follows:
[x for x in d[0]]
However, I do not know how to iterate over the entries of my list in this setting. I tried:
[x for x in d[a] for a in l] # name 'a' not defined
[x for x in d[for a in l]] # invalid syntax
You want to iterate over l, so use for element in l. Then look stuff up in your dictionary in the left-hand side, in the value-producing expression:
[d[element] for element in l]
Note that a dictionary mapping consecutive integers starting at 0 to letters isn't all that efficient; you may as well make it a list:
num_to_letter = [chr(65 + i) for i in range(4)]
This still maps 0 to 'A', 1 to 'B', etc, but without a hashing step.

Categories