How to fill array from index to another index in Python - python

How to fill an array from on index let's say 3 to 5 in an array containing 10 element without a for loop?
Input:
[0,5,8,4,6,7,5,1,3,0]
Output:
[0,5,8,'replaced','replaced','replaced',5,1,3,0]

Since lists are mutable, you can just use list slicing:
>>> lst = [0,5,8,4,6,7,5,1,3,0]
>>> lst[3:6] = ['','','']
>>> lst
[0, 5, 8, '', '', '', 5, 1, 3, 0]

One way:
arr = [0,5,8,4,6,7,5,1,3,0]
arr[3:6] = ['replaced']*(6-3)
# [0, 5, 8, 'replaced', 'replaced', 'replaced', 5, 1, 3, 0]

Here's another way to do it
>>> nums = [0,5,8,4,6,7,5,1,3,0]
>>> ['replaced' if 3 <= i <= 5 else num for i, num in enumerate(nums)]
[0, 5, 8, 'replaced', 'replaced', 'replaced', 5, 1, 3, 0]

Related

How to get indices of sorted array in descending order

I have a simple list of values of which I need the index sorted by the original value order (max to min).
Let's assume the list is
maxList = [7, 3, 6, 9, 1, 3]
The result should be:
indexedMaxList = [3, 0, 2, 1, 5, 4]
What I tried so far:
def ClusteringOrder(maxList):
sortedMaxList = maxList.copy()
sortedMaxList.sort(reverse=True)
indexedMaxList = []
for i in range(len(maxList)):
indexedMaxList.append(maxList.index(sortedMaxList[i]))
return(indexedmaxList)
Problem is obviously, doing it this way returns the index of the first occurrence of duplicate values. In this case, the double 3 will return a 1 two times, hence the result will be:
indexedMaxList = [3, 0, 2, 1, 1, 4]
Is there any simple way of doing this to get the actual positions back?
You can combine enumerate() with custom key= parameter in sorted():
maxList = [7, 3, 6, 9, 1, 3]
print([i[0] for i in sorted(enumerate(maxList), key=lambda k: k[1], reverse=True)])
Prints:
[3, 0, 2, 1, 5, 4]
import numpy
maxList = [7, 3, 6, 9, 1, 3]
print(np.flip(np.argsort(maxList)))
Output
[3 0 2 5 1 4]

Python cut array into two arrays using indices array

I have an array, let's say arr = [1, 2, 3, 4, 5, 6, 7, 8]
and another indices array: idx = [0, 3, 4, 6]
and I want to get two arrays, one is only those indices from arr: [1, 4, 5, 7]
and another one is all the rest: [2, 3, 6, 8]
Can someone help me with that? I can only think of ugly ways to do it, but it must be some function that does it elegantly.
Thanks a lot!
You could do it like this:
selected = [arr[i] for i in idx]
other = [v for i, v in enumerate(arr) if i not in idx]
If arr has no duplicates, you could also do:
other = [v for v in arr if v not in selected]
Way to do it:
a1 = [arr[x] for x in idx]
a2 = [x for x in arr if x not in a1]
With one traversal:
no, yes = both = [], []
for i, x in enumerate(arr):
both[i in idx].append(x)
Or (as commented by Chris_Rands):
yes, no = [], []
for i, x in enumerate(arr):
(yes if i in idx else no).append(x)
Though idx should either be small for this or turned into a set (same goes for the solutions in the other answers, I guess they just don't want to talk about it).
Demo:
>>> if 1:
arr = [1, 2, 3, 4, 5, 6, 7, 8]
idx = [0, 3, 4, 6]
no, yes = both = [], []
for i, x in enumerate(arr):
both[i in idx].append(x)
print('yes', yes)
print('no', no)
yes [1, 4, 5, 7]
no [2, 3, 6, 8]
There is a neat solution with numpy:
import numpy as np
arr = np.asarray([1, 2, 3, 4, 5, 6, 7, 8]) # converts your list in numpy array
idx1 = [0, 3, 4, 6]
idx2 = [1, 2, 5, 7]
arr1 = arr[idx1] # [1 4 5 7]
arr2 = arr[idx2] # [2 3 6 8]
You can use itertools for a one line solution:
import itertools
arr = [1, 2, 3, 4, 5, 6, 7, 8]
idx = [0, 3, 4, 6]
[(out_index, not_in_arr), (in_index, in_arr)] = [(a, list(b)) for a, b in itertools.groupby(sorted(arr, key=lambda x:arr.index(x) in idx), key=lambda x:arr.index(x) in idx)]
print(not_in_arr)
print(in_arr)
Output:
[2, 3, 6, 8]
[1, 4, 5, 7]
You can also map each value in arr to a dictionary, indicating if it's index is present in idx:
arr = [1, 2, 3, 4, 5, 6, 7, 8]
idx = [0, 3, 4, 6]
# converted to a set
idx_lookup = set(idx)
d = {x: True if i in idx_lookup else False for i, x in enumerate(arr)}
print(d)
Which gives this dictionay:
{1: True, 2: False, 3: False, 4: True, 5: True, 6: False, 7: True, 8: False}
I also converted idx to a set since in this case, duplicate indices are not necessary, and set/dictionary lookup is O(1). However, list lookup is O(n), so this optimization is worth it if possible.
Once you have this dictionary, you can filter out the elements you want to keep, and the rest of the elements from this:
keep = list(filter(lambda x: d[x], arr))
rest = list(filter(lambda x: not d[x], arr))
print(keep)
print(rest)
Which Outputs:
[1, 4, 5, 7]
[2, 3, 6, 8]
Note: You can also use list comprehensions above filtering of keep and rest:
keep = [x for x in arr if d[x]]
rest = [x for x in arr if not d[x]]

Split list into smaller lists based on values?

Say I have a list: [1, 2, 3, 4, -1, 5, 6, 7, -1, 0, 0, 3, 2, 1]
I want to split this list into using values -1 or 0, 0 as a delimiter:
[[1, 2, 3, 4], [5, 6, 7], [], [3, 2, 1]]
(Note the empty 3rd list)
How would I achieve this? My current solution is just a trivial loop but I'm wondering if theres a more pythonic solution (using list comprehensions) for delimiters of any length?
Current solution as requested (messy and hacky :P)
string = '|'.join([str(x) for x in data]).replace('-1', ',').replace('0|0', ',')
buckets = [x.split('|') if y for x in string.split(',')]
It's not trivial, but you can done it like this:
my_list = [1, 2, 3, 4, -1, 5, 6, 7, -1, 0, 0, 3, 2, 1]
my_list = ','.join(map(str, my_list))
my_list = [x.split(',') for y in my_list.split('0,0,') for x in y.split(',-1,')]
my_list = [map(int, x) if x != [''] else [] for x in my_list]
Using simple for loop and check conditions
Code:
lst = [1, 2, 3, 4, -1, 5, 6, 7, -1, 0, 0, 3, 2, 1,-1,0]
output_lst = []
check = 0
sample=[]
for val in lst:
if val == -1 :
output_lst.append(sample)
check = 0
sample = []
continue
if val == 0 :
if check ==1 :
output_lst.append(sample[:-1])
check = 0
sample = []
continue
check = 1
sample.append(val)
if check ==1:
output_lst.append(sample)
print output_lst
Output:
[[1, 2, 3, 4], [5, 6, 7], [], [3, 2, 1], [0]]
Try this
use one iteration for to do it.
ar = [1, 2, 3, 4, -1, 5, 6, 7, -1, 0, 0, 3, 2, 1]
data = ', '.join(map(str, ar))
import re
data = re.split(", -1,| 0, 0,",data)
bucket = []
import ast
for y in data:
hac = ast.literal_eval("["+y+"]")
bucket.append(hac)
print bucket

How to change numbers around in a list (python)

i have been working on this for 3 hours now but i have no clue how to do it
can anyone help me with this?
values = [1, 2, 3, 4, 5]
temp = values[0]
for index in range (len(values) -1):
values[index] = values [index]
values[len(values)-1] = temp
print values
i want the printed values to be in order as [2,3,4,5,1]
by simply changing those in the brackets
deque is more efficient way to do
In [1]: import collections
In [3]: dq = collections.deque([1,2,3,4,5])
In [4]: dq.rotate(-1)
In [5]: dq
Out[5]: deque([2, 3, 4, 5, 1])
What you are trying to achieve is not available in the python libraries but you can leverage slicing to rotate list
Implementation
def rotate(seq, n = 1, direc = 'l'):
if direc.lower() == 'l':
seq = seq[n:] + seq[0:n]
else:
seq = seq[-n:] + seq[:-n]
return seq
Demonstration
>>> rotate(values)
[2, 3, 4, 5, 1]
>>> rotate(values,2,'l')
[3, 4, 5, 1, 2]
>>> rotate(values,2,'r')
[4, 5, 1, 2, 3]
Simple but powerful slice syntax:
values = [1, 2, 3, 4, 5]
shifted = values[1:]+values[:1]
assert shifted == [2, 3, 4, 5, 1]
How about time one-liner, in the spirit of sleepsort:
while values != [2, 3, 4, 5, 1]: random.shuffle(values)

Python - How to remove similar elements from a list?

For example I have a list:
L = [1, 2, 2, 3, 1, 1, 6, 10, 1, 3]
And I want to remove all 1's from the list, so that I would get:
L = [2, 2, 3, 6, 10, 3]
I tried iterating over the list and then deleting the element if it equals the element I want to delete (1 in this case), but turns out you can't iterate and delete stuff from a list at the same time since it messes up the counting. The best thing I've come up with is just construct a new list L2 that doesn't contain any of the 1's and then put that into L, but is there a solution that only involves mutating L?
but is there a solution that only involves mutating L?
You can rather iterate over a copy of your List - L[:], and remove element from L. That won't mess up counting.
If you really don't want to create a new list, you would have to iterate in reverse using range(len(L) - 1, -1, -1), but that won't be 'Pythonic' anymore.
>>> for x in L[:]:
... if x == 1:
... L.remove(x)
...
>>> L
[2, 2, 3, 6, 10, 3]
However, you can also use List Comprehension:
>>> L = [1, 2, 2, 3, 1, 1, 6, 10, 1, 3]
>>> L[:] = [x for x in L if x != 1]
>>> L
[2, 2, 3, 6, 10, 3]
Using the filter built-in:
>>> L = [1, 2, 2, 3, 1, 1, 6, 10, 1, 3]
>>> filter(lambda x: x is not 1, L)
[2, 2, 3, 6, 10, 3]
Or you can assign it back to L:
>>> L = [1, 2, 2, 3, 1, 1, 6, 10, 1, 3]
>>> L = filter(lambda x: x is not 1, L)
>>> L
[2, 2, 3, 6, 10, 3]
You can also wrap this concept into methods, to be able to specify a list of items to include/exclude:
def exclude(collection, exclude_list):
return filter(lambda x: x not in exclude_list, collection)
def include(collection, include_list):
return filter(lambda x: x in include_list, collection)
>>> L = [1, 2, 2, 3, 1, 1, 6, 10, 1, 3]
>>> L = exclude(L, [1])
>>> L
[2, 2, 3, 6, 10, 3]
If you don't want to mutate the list or generate any new copy of it. You can loop from end to begin and use index:
>>> for i in range(len(L)-1, -1, -1):
... if L[i] == 1:
... del L[i]
This is awkward to do in python without making a copy of the list...
This will do it without making a copy.
a = range(6) # Some array [0,1,2,3,4,5]
i=0
while i < len(a):
if a[i] == 4:
del a[i]
else:
i += 1
OUTPUT
>>> a
[0, 1, 2, 3, 5]

Categories

Resources