Related
lets suppose A = [1, 2, 3, 1, 2, 3, 2, 1, 3, 1, 2, 3].
If B is a subset of A, say [2, 1, 3];
I want to remove B from A in the same order to get [1, 2, 3, 1, 2, 3, 1, 2, 3].
Here's the code I used:
_set = [
1, 2, 3,
1, 2, 3,
2, 1, 3,
1, 2, 3
]
subset = [2, 1, 3]
def remove_subset(_set, subset):
for i in subset:
_set.remove(i)
return _set
print(remove_subset(_set, subset))
But it gives the output [1, 2, 3, 2, 1, 3, 1, 2, 3].
The expected output is: [1, 2, 3, 1, 2, 3, 1, 2, 3].
As written, you're removing the individual elements without paying attention to the order they appear. It looks like you want to delete the elements of the subset only if they appear contiguously in the same order as they do in the subset.
Sadly, this is something Python lists won't do for you (there is no equivalent to str.replace that allows you to remove a fixed sequence wherever it occurs). So you're stuck finding the index where your subsequence occurs and deleting it from the list:
for i in range(len(lst)): # Renamed set to lst, since it is a list, and to avoid shadowing set constructor
if lst[i:i+len(sublst)] == sublst: # Renamed subset to sublst to match
del lst[i:i+len(sublst)] # We found a place where the sublst begins, slice it out
break
This only removes one copy (to avoid issues with mutating a list as you iterate over it, or considering how to handle it if the sublist can overlap itself in the main list).
Side-note: This (iterating over slices of a sequence) is basically the only circumstance in which iterating over sequence indices is the Pythonic solution (there are ways to avoid the unPythonic for i in range(len(lst)): involving enumerate and zip and iter and explicit sequence multiplication and star-unpacking, but they're so ugly it's not worth the bother).
One way could be to convert your lists to strings and use the .replace method of strings -
a = [1, 2, 3, 1, 2, 3, 2, 1, 3, 1, 2, 3]
b = [2, 1, 3]
str_a = ''.join(map(str, a))
str_b = ''.join(map(str, b))
str_a_b_removed = str_a.replace(str_b, '')
list(map(int, list(str_a_b_removed)))
Output
[1, 2, 3, 1, 2, 3, 1, 2, 3]
This question already has an answer here:
flat list as a result of list comprehension [duplicate]
(1 answer)
Closed 12 months ago.
I have a list w where w[i] represents the number of times i should be present in the final result.
For example, if:
w = [1, 3, 4]
then the resulting list should be:
[0, 1, 1, 1, 2, 2, 2, 2]
Notice there is one 0, three 1's, and four 2's.
I have tried to accomplish this with the list comprehension:
w_list = [[i]*w[i] for i in range(len(w))]
but of course this doesn't quite work, giving me this:
[[0], [1, 1, 1], [2, 2, 2, 2]]
How can I write a list comprehension to get me the desired result, like in the example?
You could use a double loop to flatten w_list:
w_list = [x for num, i in enumerate(w) for x in [num] * i]
or
w_list = [x for i in range(len(w)) for x in [i]*w[i]]
Output:
[0, 1, 1, 1, 2, 2, 2, 2]
Here's an alternative solution you might like.
w = [1, 3, 4]
print([i for i in range(len(w)) for _ in range(w[i])])
results in [0, 1, 1, 1, 2, 2, 2, 2] as desired.
Alternatively, [i for i,n in enumerate(w) for _ in range(n)] accomplishes the same thing.
Given the following arrays (arr,indices) ,I need to sort the array with respect to (i[0])th index in ascending order if i[1] equals 0 and descending order if i[1] equals 1 ,where i refers to each element of the indices array.
Constraints
1<= len(indices) <=10
1<= len(arr) <=10^4
Example
arr=[[1,2,3],[3,2,1],[4,2,1],[6,4,3]]
indices=[[2,0],[0,1]]
required output
[[4,2,1],[3,2,1],[6,4,3],[1,2,3]]
Explanation
first arr gets sorted with respect to 2nd index as (indices[0][0]=2) in ascending order as (indices[0][1]=0)
[[3,2,1],[ 4,2,1],[1,2,3],[6,4,3]]
then it gets sorted with 0th index as (indices[1][0]=0) in descending order as (indices[1][1]=1)
[[4,2,1],[3,2,1],[6,4,3],[1,2,3]]
Note
arr,indices need to be taken as input , so it is not possible for me to write arr.sort(key=lambda x: (x[2],-x[0]))
My Approach
I have tried the following but it is not giving the correct output
arr.sort(key=lambda x:next(x[i[0]] if i[1]==0 else -x[i[0]] for i in indices))
My output
[[3,2,1],[4,2,1],[1,2,3],[6,4,3]]
Expected output
[[4,2,1],[3,2,1],[6,4,3],[1,2,3]]
This one requires a very complex key. It looks to me like you have many different layers of sorting, here, and earlier elements of indices take precedence over later elements, when sort order would be affected.
I think what the sorting key needs to do is return a tuple/iterable, where the first element to sort by is whatever the first element of indices says to do, and the second element to sort by (in case of a tie in the first) is whatever the second element of indices says to do, and so on.
In which case you'd want something like this (a nested comprehension inside the key lambda, to generate that tuple (or, list, in this case)):
arr=[[1,2,3],[3,2,1],[4,2,1],[6,4,3]]
indices=[[2,0],[0,1]]
out = sorted(arr, key=lambda a: [
(-1 if d else 1) * a[i]
for (i, d) in indices
])
# [[4, 2, 1], [3, 2, 1], [6, 4, 3], [1, 2, 3]]
For sorting numbers only, you can use a quick hack of "multiply by -1 to sort descending instead of ascending". Which I did here.
You could use the stability:
from operator import itemgetter
for i, r in reversed(indices):
arr.sort(key=itemgetter(i), reverse=r)
This doesn't use the negation trick, so it also works for data other than numbers.
Check this out:
>>> a
[[6, 4, 3], [4, 2, 1], [3, 2, 1], [1, 2, 3]]
>>> i
[[2, 0], [0, 1]]
>>> for j in enumerate(i):
... a.sort(key=lambda x:x[j[1][0]],reverse=False if j[1][1]==0 else True)
... print(a)
...
[[3, 2, 1], [4, 2, 1], [1, 2, 3], [6, 4, 3]]
[[6, 4, 3], [4, 2, 1], [3, 2, 1], [1, 2, 3]]
Is this what you want?
I think in your second example is small mistake. It should be
[[6, 4, 3], [4, 2, 1], [3, 2, 1], [1, 2, 3]]
rather than
[[4,2,1],[3,2,1],[6,4,3],[1,2,3]]
this is under
then it gets sorted with 0th index as (indices[1][0]=0) in descending order as (indices[1][1]=1)
I know how to delete an element in a list when it does not have a certain size like:
x = [[1,2,3],[1,2,3],[1,2,3],[1,2,3],[1,2,3],[1,2],[1,2,3],[1,2,3],[1,2,3,4]]
y = [s for s in x if len(s) == len(x[0])]
Where x is the original list, and y is the new list. As you can see in the first one there is one entry which is not as long as the others, and one which is longer then the others.
I want to delete an element each time it does not have the same length as the majority of elements in the list. The showed approach works as long as the first element in the list has the same length as the majority of the elements.
So the question is how to get the most common length of the elements? Without a loop iterating over the length. The mean will not work, because the mean will not represent the majority of length but the mean length of elements (e.g. lengths 3,3,3,30 will give a mean of ~ 10, while the majoritiy of lengths is 3.)
You can use a collections.Counter object to keep track of the counts of all the lengths, then filter using the most_common length:
from collections import Counter
x = [[1,2,3],[1,2,3],[1,2,3],[1,2,3],[1,2,3],[1,2],[1,2,3],[1,2,3],[1,2,3,4]]
lens = Counter(len(i) for i in x)
y = [s for s in x if len(s) == lens.most_common(1)[0][0]]
print y
# [[1, 2, 3], [1, 2, 3], [1, 2, 3], [1, 2, 3], [1, 2, 3], [1, 2, 3], [1, 2, 3]]
Note that if there is tie, one of the lengths is selected randomly.
The most common value is called the "mode" (statistically speaking) so to get the modal value just use statistics.mode (but it requires python 3.4+):
>>> from statistics import mode
>>> l = [[1,2,3],[1,2,3],[1,2,3],[1,2,3],[1,2,3],[1,2],[1,2,3],[1,2,3],[1,2,3,4]]
>>> most_common_length = mode([len(sublist) for sublist in l])
>>> most_common_length
3
>>> [sublist for sublist in l if len(sublist) == most_common_length]
[[1, 2, 3], [1, 2, 3], [1, 2, 3], [1, 2, 3], [1, 2, 3], [1, 2, 3], [1, 2, 3]]
In case statistics.mode is too slow (or you're using an older Python) there's also an implementation in scipy:
>>> from scipy.stats import mode
>>> most_common_length = mode([len(sublist) for sublist in l]).mode[0]
Consider the array a= [1, 2, 3, 1, 2, 3]. Now suppose I want to remove all the 2s in this array in python. So I apply a.remove(2). However the result which comes out is [1, 3, 1, 2, 3], i.e the only first 2 is removed. How can I remove all the 2s which appear in an array? In general, given an array and an element p, how can I remove all the elements of the array which are equal to p?
Edit:- I think I should mention this, this question has been inspired from a Brilliant computer science problem.
Use a list comprehension to build a replacement list, where all elements are not equal to p:
a = [i for i in a if i != p]
Note that in Python, the datatype is called a list, not an array.
You can use filter().
>>> a= [1, 2, 3, 1, 2, 3]
>>> filter(lambda x: x != 2, a)
[1, 3, 1, 3]
In a function :
>>> def removeAll(inList, num):
return filter(lambda elem: elem != num, inList)
>>> removeAll(a, 2)
[1, 3, 1, 3]