Removing indexes from a list - python

I'm facing a somewhat troubling problem: I have a list (for example (2, 5, 7, 3, 8)) and I need to remove a couple of those but not all. Let's say I need to remove indexes 1, 3 and 4 and I want to do that in a loop. Is there anyway (in Python or logically) to remove those indexes easily in a loop.
If I have a list remIndexes = (1, 3, 4), as soon as I remove index 1, everything moves down one, so now I have (2, 7, 3, 8) and the indexes for the numbers I wanted to remove are shifted down by one.
Does python provide a neat way of doing this or am I going to have to order the list remIndexes and then go backwards through the list?
Note: remIndexes should be in order, but it could potentially not be in order. Ordering it isn't very hard, however.
UPDATE:
Why does
lst = [1, 2, 3, 4, 5, 6, 7, 8, 9, 0]
for ind, num in enumerate(lst):
print lst.pop(ind)
actually work????? (It prints 2 4 6 8 0 each on a newline.)
Does python freeze a list while you are in a for loop?

Iterate the reversed indexes:
>>> lst = [2, 5, 7, 3, 8]
>>> indexes = 1, 3, 4
>>> for i in reversed(indexes):
... del lst[i]
...
>>> lst
[2, 7]
Or use sorted(indexes, reverse=True) if the indexes is not sorted.
Using list comprehension with enumerate:
>>> lst = [2, 5, 7, 3, 8]
>>> indexes = 1, 3, 4
>>> indexes = set(indexes) # `x in set` is faster than `x in tuple/list`
>>> [x for i, x in enumerate(lst) if i not in indexes]
[2, 7]

Related

List containing only every second second pair of elements

I am new to python and so I am experimenting a little bit, but I have a little problem now.
I have a list of n numbers and I want to make a new list that contains only every second pair of the numbers.
So basically if I have list like this
oldlist = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
then I want that the new list looks like this
newlist = [3, 4, 7, 8]
I already tried the slice() function, but I didn't find any way to make it slice my list into pairs. Then I thought that I could use two slice() functions that goes by four and are moved by one, but if I merge these two new lists they won't be in the right order.
If you enumerate the list, you'd be taking those entries whose indices give either 2 or 3 as a remainder when divided by 4:
>>> [val for j, val in enumerate(old_list) if j % 4 in (2, 3)]
[3, 4, 7, 8]
a = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
b = [a[i] for i in range(len(a)) if i%4 in (2,3)]
# Output: b = [3, 4, 7, 8]
Here, we use the idea that the 3rd,4th,7th,8th..and so on. indices leave either 2 or 3 as the remainder when divided by 4.
first_part = oldList[2::4] # every 4th item, starting from the 3rd item
second_part = oldList[3::4] # every 4th item starting from the 4th item
pairs = zip(first_part, second_part)
final_result = chain.from_iterable(pairs)
Break this problem in to parts.
first = oldlist[2::4]
second = oldlist[3::4]
pairs = [(x, y) for x, y in zip(first, second)]
Now unwrap the pairs:
newlist = [x for p in pairs for x in p]
Combining:
newlist = [z for p in [(x, y) for x, y in zip(oldlist[2::4], oldlist[3::4])] for z in p]
I would firstly divide original list into two lists, with odd and even elements. Then iterate over zip of them.
old = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
result = list()
part1, part2 = old[::2], old[1::2]
for i, z in enumerate(zip(part1,part2)):
if i % 2 == 0:
result.extend(z)
You could use a double range:
oldlist = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
newlist = []
for i,j in zip(range(2, len(oldlist), 4), range(3, len(oldlist), 4)):
newlist += [oldlist[i], oldlist[j]]
#> newlist: [3, 4, 7, 8]
import more_itertools
oldlist = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
[*more_itertools.interleave(oldlist[2::4], oldlist[3::4])]
# [3, 4, 7, 8]
oldlist[2::4], oldlist[3::4]: slice 4th item
[*more_itertools.interleave(...)]: interleave the two above and convert back to a list
Here is what I have come up with:
oldList = list(range(1,10))
newList = []
for i in oldList:
if (i%2 == 0) and (i%4 != 0):
try:
newList.append(i+1)
newList.append(i+2)
except IndexError:
break
Result:
>>> newList
[3, 4, 7, 8]

How to split a numpy array based on a tuple content? [duplicate]

This question already has an answer here:
Create index list for np.split from the list that already has number for each section
(1 answer)
Closed 3 years ago.
Let's say I've got an array [0, 1, 2, 3, 4, 5, 6, 7] and a tuple: (3, 3, 2).
I'm looking for a way to split my array to 3 array based on my tuple data:
[0, 1, 2]
[3, 4, 5]
[6, 7]
I can write a simple code like this to get what I want, however I'm looking for a correct and pythonic way to do this:
I used lists for simplicity.
a = [0, 1, 2, 3, 4, 5, 6, 7]
b = (3, 3, 2)
pointer = 0
for i in b:
lst = []
for j in range(i):
lst.append(a[pointer])
pointer += 1
print(lst)
Or this one:
a = [0, 1, 2, 3, 4, 5, 6, 7]
b = (3, 3, 2)
pointer = 0
for i in b:
lst = a[pointer:pointer+i]
pointer += i
print(lst)
Results:
[0, 1, 2]
[3, 4, 5]
[6, 7]
you can use the split method of numpy
import numpy as np
a = [0, 1, 2, 3, 4, 5, 6, 7]
b = (3, 3, 2)
c = np.split(a, np.cumsum(b)[:-1])
for r in c:
print(r)
np.split(a, b) splits a by the indices in b along a given axis(0 by default).
If you don't want to modify your input list, you can use an iterator and the itertools module.
>>> from itertools import islice
>>> a = [0, 1, 2, 3, 4, 5, 6, 7]
>>> b = (3, 3, 2)
>>> i = iter(a)
>>> [list(islice(i, x)) for x in b]
[[0, 1, 2], [3, 4, 5], [6, 7]]
In the first step you create an iterator, which starts at the first element of a. Then you iterate in a list comprehension over your numbers in b and in each step you pull accordingly many elements from the iterator and store them in your result list.
One simpler way is this:
a = [0, 1, 2, 3, 4, 5, 6, 7]
b = (3, 3, 2)
for ind in b:
print(a[:ind])
a = a[ind:]
It loops through slice sizes in b while shortening the original array every time. You can easily append the resulting slices as sublists if you need them for something else. It's almost like one of your solutions except it doesn't use any extra variables and iterates directly through elements of b.
Also, I wouldn't call variables a and b - surely not in this case where variables have clear meanings that you can express through their names. More meaningful names lessen bugs number and make code more clear, becomes a real difference with larger/more complex code. I'd call a at least in_list and b slices, but with more context this could be better.
The most "concise" syntax would be :
ex_array = [0, 1, 2, 3, 4, 5, 6, 7]
extuple = (3, 3, 2)
result = [ex_array[sum(extuple[:iii]):sum(extuple[:iii])+extuple[iii]] for iii in range(len(extuple))]
result would be a list of the expected sub-lists
Re-using the pairwise function from Compare two adjacent elements in same list, you could also:
from itertools import accumulate
from more_itertools import pairwise
a = [0, 1, 2, 3, 4, 5, 6, 7]
b = (3, 3, 2)
[a[slice(*s)] for s in pairwise(accumulate((0,)+b))]
That begin said, the np.split answer is probably faster (and easier to read).

I need to create a list containing all the sums of a list taken three at a time, ie, add first 3 elements then the next 3 [duplicate]

This question already has answers here:
How do I split a list into equally-sized chunks?
(66 answers)
Closed 6 years ago.
I need to add the first three elements of a list then add the next three elements of a list and so forth. This is the code I have got so far:
def get_triple_sums_list(a_list):
new_list = []
for numbers in range(0,len(a_list)):
numbers = sum(a_list[:3])
new_list.append(numbers)
return new_list
if a_list == []:
return []
For the list:
[1, 5, 3, 4, 5, 2]
This in turn gives me the result:
[9]
I need to get
[9, 11]
If the remaining numbers is less than 3, it gives me the remainder of the sum ie,
[1, 6, 2, 4, 3]
Gives me
[9, 7]
And
[1, 6, 2, 4]
Give me
[9, 4]
Let's analyze your code!
def get_triple_sums_list(a_list):
new_list = []
for numbers in range(0,len(a_list)):
numbers = sum(a_list[:3]) #You should be using the variable
#numbers here somehow.
#^^^^^^^ - You are overwriting the for-loop index.
new_list.append(numbers)
return new_list #Why are you returning here? You should be
#appending to `new_list`.
if a_list == []:
return []
Here is the fixed code:
def get_triple_sums_list(a_list):
new_list = []
for index in range(0,len(a_list), 3): #Range takes a 3rd param!
total = sum(a_list[index:index+3])#Get all the elements from the
#index to index+3
new_list.append(total)
return new_list
UPDATE: It seems there's a shortening contest going on -- and I do not want to be left behind. Here's an ugly version I'd like to add to the list.
>>> a = [1,2,3,4,5,6,7,8]
>>> a += [0]*(len(a)%3) #For people who are too lazy to import izip_longest
>>> map(sum,zip(a[::3], a[1::3], a[2::3]))
[6, 15, 15]
I like SuperSaiyan's approach of explaining things, I'll be the one who shortens it a bit. You can get the same result with a single comprehension:
l = [1, 5, 3, 4, 5, 2]
n = 3
r = [sum(l[i:i+n]) for i in range(0, len(l), n)]
print(r)
[9, 11]
l[i:i+n] splits the list in even chunks of length 3 and sum takes care of adding these together. Using the for i in range(0, len(l), n) we dictate that this operation is to happen for ceil(len(l) / 3) times.
Just cuz I like to be different.
l = [1, 5, 3, 4, 5, 3, 42]
g = lambda l,s: [sum(l[i:i+s]) for i in range(0,len(l),s)]
print g(l,3)
#>> [9,12,42]
The other answer mentions the fault with your code. However do note that it's always easier to use a list comprehension in these cases.
>>> l = [1, 5, 3, 4, 5, 2]
>>> [sum(l[i:i+3]) for i in range(0,len(l),3)]
[9, 11]
It also works for un-mod-3 lists
>>> l = [1, 5, 3, 4, 5]
>>> [sum(l[i:i+3]) for i in range(0,len(l),3)]
[9, 9]
See What does "list comprehension" mean? How does it work and how can I use it? for more details about a list comprehension.
Here is a slightly different way of doing it using zip_longest from itertools (izip_longest in python2), it splits the list in three lists then zip them to get packs of three elements and finally sums the packs:
from itertools import zip_longest
a=[1, 6, 2, 4, 3]
b=zip_longest(a[0::3],a[1::3],a[2::3],fillvalue=0)
result=[sum(x) for x in b]
>>>[9, 7]
Alternatively, you may achieve it by using map() with lambda function as:
>>> my_list = [1, 5, 3, 4, 5, 2]
>>> list(map(lambda x: sum(my_list[x:x+3]), range(0, len(my_list), 3)))
[9, 11]

Removing the duplicate entries from a list by editing the list

Have a list arr = [1,3,4,5,2,3,4,2,5,7,3,8,1,9,6,2,1,2,1,3,4,3,4,6,9]
want to remove the duplicate values so that the original list should contains single instances of all elements. Do not want to create a extra list and append the elements from list. Also do not want to use inbuilt "set".
Tried to do that with some code as below:
l = len(arr)
for x in range(l):
for y in range(x+1,l):
if arr[x] == arr[y]:
del arr[y]
Tried the above code and its throwing error
"IndexError: list index out of range"
What I understand is whiling deleting the value the size of the list is changing for which its throwing the error. So I made the below changes. But still its failing with same error:
l = len(arr)
for x in range(l):
for y in range(x+1,l):
if arr[x] == arr[y]:
t = y
del arr[y]
y = t - 1
Can some one help me out on this?
Thanks in Advance.
You are trying to make the code more efficient by caching the length of the list in the local variable l. However, that is not helpful because the list is being trimmed inside the loop, and you are not keeping the cached length variable in sync.
for index in range(len(arr)-1,0,-1):
if arr[index] in arr[:index]:
del arr[index]
By going backwards through the array and looking for earlier occurrences of each element, you can avoid having to worry about the length of the list changing all the time.
This method also preserves the order in which elements occur in the original array. Note the instruction is to only remove duplicates (a.k.a. subsequent occurrences).
For example the list [9,3,4,3,5] should reduce to [9,3,4, 5] as the second occurrence of 3 is considered a duplicate and should be removed.
How about this approach:
>>> set(arr)
set([1, 2, 3, 4, 5, 6, 7, 8, 9]) #Just to compare it with the results below.
>>> arr = [1,3,4,5,2,3,4,2,5,7,3,8,1,9,6,2,1,2,1,3,4,3,4,6,9]
>>> arr.sort()
>>> arr
[1, 1, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3, 3, 4, 4, 4, 4, 5, 5, 6, 6, 7, 8, 9, 9]
>>> for i in arr:
while arr.count(i) > 1:
del arr[i]
>>> arr
[1, 2, 3, 4, 5, 6, 7, 8, 9]
Another approach is to find, after sorting your list, the length of the sublist to delete for each number:
>>> arr = [1,3,4,5,2,3,4,2,5,7,3,8,1,9,6,2,1,2,1,3,4,3,4,6,9]
>>> arr.sort()
>>> arr
[1, 1, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3, 3, 4, 4, 4, 4, 5, 5, 6, 6, 7, 8, 9, 9]
>>> for i,j in enumerate(arr):
del arr[i+1:i+arr.count(j)]
>>> arr
[1, 2, 3, 4, 5, 6, 7, 8, 9]

Compare each element in a list to all others

Is there a way to compare all elements of a list (ie one such as [4, 3, 2, 1, 4, 3, 2, 1, 4]) to all others and return, for each element, the number of other elements it is different from (ie, for the list above [6, 7, 7, 7, 6, 7, 7, 7, 6])? I then will need to add the numbers from this list.
li = [4, 3, 2, 1, 4, 3, 2, 1, 4]
from collections import Counter
c = Counter(li)
print c
length = len(li)
print [length - c[el] for el in li]
Creating c before executing [length - c[el] for el in li] is better than doing count(i) for each element i of the list, because that means that count() do the same count several times (each time it encounters a given element, it counts it)
By the way, another way to write it:
map(lambda x: length-c[x] , li)
You can get similar counter with count() method.
And subtract the total number.
Do it in one line with a comprehension list.
>>> l = [4, 3, 2, 1, 4, 3, 2, 1, 4]
>>> [ len(l)-l.count(i) for i in l ]
[6, 7, 7, 7, 6, 7, 7, 7, 6]
For Python 2.7:
test = [4, 3, 2, 1, 4, 3, 2, 1, 4]
length = len(test)
print [length - test.count(x) for x in test]
You could just use the sum function, along with a generator expression.
>>> l = [4, 3, 2, 1, 4, 3, 2, 1, 4]
>>> length = len(l)
>>> print sum(length - l.count(i) for i in l)
60
The good thing about a generator expression is that you don't create an actual list in memory, but functions like sum can still iterate over them and produce the desired result. Note, however, that once you iterate over a generator once, you can't iterate over it again.

Categories

Resources