Related
Suppose I have a list a=[1, 3, 4, 5, 7] and another list b=[0,0,1,1,3].
Now I want to filter a to make a new list where the corresponding position in b is 0 or 3. If I only want b to be 0, it's simply a = a[b==0], but now it's filtering based on a subset.
What I did is :
subset = [0, 1]
a = a[b in subset]
which is not correct and the error goes:ValueError: The truth value of an array with more than one element is ambiguous. Use a.any() or a.all()
I wonder what is the correct way to do so. Thanks!
If I understand your question right then you're looking for np.isin:
a = np.array([1, 3, 4, 5, 7])
b = np.array([0, 0, 1, 1, 3])
print(a[np.isin(b, [0, 3])])
Prints:
[1 3 7]
new_list = [i[0] for i in zip(a,b) if i[1] in [0,1]]
This uses a concept known as list comprehension.
It first creates a zip object that looks like
[(1, 0), (3, 0), (4, 1), (5, 1), (7,3)]
The list comprehension cycles through all the tuples, and filters for all the ones where the second element is either 0 or 1. And returns the first part of that
You can do with filter,
In [18]: d = dict(zip(a,b))
In [19]: list(filter(lambda x:d.get(x) in (0,1), d))
Out[19]: [1, 3, 4, 5]
I am new to python and I have a question
A = [3,2,4,1]
N = len(A)
B = sorted(range(N), key = lambda i: A[i])
print(B)
output #[3, 1, 0, 2]
input #A = [7,2,4,1]
output #[3, 1, 2, 0]
I do not understand the output ?? Can anyone explain to me?
Let's talk about the specific example you have used
A = [3, 2, 4, 1]
N = len(A) . # N = 4
B = sorted(range(N), key = lambda i: A[i]) # sorted([0,1,2,3], key= lambda i:A[i])
Basically you are trying to sort [0,1,2,3] based on the values A[i] which are [3,2,4,1]
Now, A[3] < A[1] < A[0] < A[2]
And so you get the answer as [3, 1, 0, 2]
In the sorted function the first element is the item you would like to sort. If you can you sort a generator that is converted to a list of size 4. The sorting function sorts according to the value given by the anonymous function.
In your case - A = [3, 2, 4, 1]
List to sort - [0, 1, 2, 3]. Keys for each element [3, 2, 4, 1]. Basically you can imagine you sort [(0, 3), (1, 2), (2, 4), (3, 1)] according to the second element and then left with the first element and this results [3, 1, 0, 2] you get.
I wish to input an n*m array and the resulting output be an array containing the different combinations of the row elements.
Here's an example to clarify (albeit an extremely simple case):
I wish to input an array of the following shape:
[[1, 2, 3]
[2, 5, 6]]
And wish to receive the following output:
[[1,2], [1,5], [1,6], [2,5], [2,6], [3,2], [3,5], [3,6]]
As you can see [2,2] is not included because of repetition.
I can write quick and dirty code containing nested for loops when the input dimensions are know a priori:
A = [[1, 2, 3], [2, 5, 6]]
m = len(A[0])
for i in range(0, m):
for j in range(0, m):
if A[0][i]!=A[1][j]: #check and eliminate repetition
combined.append([A[0][i],A[1][j])
choice_num.append([i+1, j+1]) #See (**) below
I would really like to know how to implement this as a recursive function so given some input n-D array, A, one can simply call it as:
recursive_looper(A)
(**) Another feature that I would like is for the function to output the column number corresponding to the element used in the combination so we get two outputs:
element values: [[1,2], [1,5], [1,6], [2,5], [2,6], [3,2], [3,5], [3,6]]
element position: [[1,1], [1,2], [1,3], [2,2], [2,3], [3,1], [3,2], [3,3]]
Any tips or suggestions would be greatly appreciated!!
Edit: I am open to any solution that can achieve the desired output. Recursion was simply the first thing that came to mind.
Edit 2 (Extended capabilities): This code must not be restricted to a specific list input shape but be extensible to any array of shape (n,m).
I'll provide an example for where the code breaks down. The work-around was implementing n-1 conditional statements, which I would like to avoid because the array shape must be known a priori.
A = [[2, 4, 1, 11, 3], [3, 2, 1, 4, 11], [2, 3, 4, 17, 13]]
If I do not make any modifications to your indexing/filter I receive the following output for the 'filtered' list:
#[[2, 3, 2], [2, 3, 3], [2, 3, 4], [2, 3, 17], [2, 3, 13], [2, 1, 2], ..., [3, 11, 13]]
Immediately I notice that it only compared element position 0 with position 1 for 'likeness', hence why the first combination contains two 2's.
I can make a modification to the Index grabber and filter loop which looks like so:
for i in range(0, len(projects_master)-2):
indexes = [idx for idx, t in enumerate(prod) if t[i] == t[i+1] or t[i]==t[i+2] or t[i+1] == t[i+2] ]
res = []
for i in range(0, len(A)-2):
res.append(list(filter( lambda v: v[i] != v[i+1] and v[i] != v[i+2] and v[i+1] != v[i+2], prod)))
result = [list(t) for t in res[0]]
This does give the correct output, but like I said, I needed to write out n-1 t[i] and v[i] conditions. How can this be done automatically?
EDIT 3 - FINAL
Thanks a bunch to those who provided different approaches to help me achieve the same end goal. I took some insight from each and wrote something that makes sense to me and seems to function well for any input. The code which filters duplicates and removes them from the combinations is shown below:
ind_remove = []
for i in range(0, len(prod)):
if len(prod[i]) != len(set(prod[i])):
ind_remove.append(i)
adder=0
for i in ind_remove:
del prod[i-adder]
adder=adder+1 #takes into account change in indices after an element is deleted.
You can use itertools.product to generate the required combinations, which works like a cartesion product between two sets to generate the combinations.
So it the lists have been [[1, 2], [3, 4]], the cartesian product within the sublists will be
[[1, 3], [1, 4], [2, 3], [2, 4]]
from itertools import product
a = [[1, 2, 3], [2, 5, 6]]
# Generate all possible products, *a gives you two lists
prod = list(product(*a))
#[(1, 2), (1, 5), (1, 6), (2, 2), (2, 5), (2, 6), (3, 2), (3, 5), (3, 6)]
#Get the list of duplicate indexes
indexes = [idx for idx, t in enumerate(prod) if t[0] == t[1] ]
print(indexes)
#[3]
#Remove tuples who are duplicates
res = list(filter( lambda v: v[0] != v[1], prod))
print(res)
#[(1, 2), (1, 5), (1, 6), (2, 5), (2, 6), (3, 2), (3, 5), (3, 6)]
#Convert the tuples to list
result = [list(t) for t in res]
print(result)
#[[1, 2], [1, 5], [1, 6], [2, 5], [2, 6], [3, 2], [3, 5], [3, 6]]
You can use a function that iterates over the items of the first list of the given list of lists and merge each item with the combinations from the recursive calls:
def nonrepetitive_product(lists):
if not lists:
yield []
return
first, *rest = lists
combinations = list(nonrepetitive_product(rest))
for item in first:
for combination in combinations:
if item not in combination:
yield [item, *combination]
so that given:
l = [[1, 2, 3], [2, 5, 6]]
list(nonrepetitive_product(l)) returns:
[[1, 2], [1, 5], [1, 6], [2, 5], [2, 6], [3, 2], [3, 5], [3, 6]]
If you want the positions and values for any number of rows, you'd be better off using itertools.product and enumerate together. Filtering is a little tricky, but it can be done:
import itertools
A = [[1, 2, 3], [2, 5, 6], [7, 8, 3]]
prod = itertools.product(*map(enumerate, A)) # yields ((i,x),(j,y),(k,z),...) nested tuples
transposed = ([*zip(*pairs)] for pairs in prod) # yields ((i,j,k,...), (x,y,z,...)) 2-tuples
filtered = [(ijk, xyz) for ijk, xyz in transposed if len(xyz) == len(set(xyz))] # filter dupes
indexes, values = zip(*filtered) # you might find `filtered` more useful than separate lists
Say I have a list of lists, e.g:
x = [[0,1,2,3],[4,5],[6,7,8,9,10]]
And I have the 'flat' indices of the elements I wish to target, i.e, the indices of the elements I want to select from the list if it were flattened into a 1d list:
flattened_indices = [0,1,4,9]
# # # #
flattened_list = [0,1,2,3,4,5,6,7,8,9,10]
How do I convert the 1.d. indices into 2.d. indices that would allow me to recover the elements from the original nested list? I.e. in this example:
2d_indices = [(0,0), (0,1), (1,0), (2,3)]
Here is a way to do that:
from bisect import bisect
import itertools
# Accumulated sum of list lengths
def len_cumsum(x):
return list(itertools.accumulate(map(len, x)))
# Find 2D index from accumulated list of lengths
def find_2d_idx(c, idx):
i1 = bisect(c, idx)
i2 = (idx - c[i1 - 1]) if i1 > 0 else idx
return (i1, i2)
# Test
x = [[0, 1, 2, 3], [4, 5], [6, 7, 8, 9, 10]]
indices = [0, 4, 9]
flattened_list = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
c = len_cumsum(x)
idx_2d = [find_2d_idx(c, i) for i in indices]
print(idx_2d)
>>> [(0, 0), (1, 0), (2, 3)]
print([x[i1][i2] for i1, i2 in idx_2d])
>>> [0, 4, 9]
If you have many "flat" indices, this is more effective than iterating the nested list for each index.
I guess you could put these index pairs in a dict, then just reference the dict from indices at the end and create a new list:
x = [[0,1,2,3],[4,5],[6,7,8,9,10]]
indices = [0,4,9]
idx_map = {x: (i, j) for i, l in enumerate(x) for j, x in enumerate(l)}
result = [idx_map[x] for x in indices]
print(result)
Which results in:
[(0, 0), (1, 0), (2, 3)]
But this is not optimal since its quadratic runtime to create idx_map. #jdehesa's solution using bisect is much more optimal.
How can I print the most common element of a list without importing a library?
l=[1,2,3,4,4,4]
So I want the output to be 4.
You can get the unique values first:
l = [1, 2, 3, 4, 4, 4]
s = set(l)
then you can create list of (occurrences, value) tuples
freq = [(l.count(i), i) for i in s] # [(1, 1), (1, 2), (1, 3), (3, 4)]
get the "biggest" element (biggest number of occurrences, the biggest value if there are more than one with the same number of occurrences):
result = max(freq) # (3, 4)
and print the value:
print(result[1]) # 4
or as a "one-liner" way:
l = [1, 2, 3, 4, 4, 4]
print(max((l.count(i), i) for i in set(l))[1]) # 4
lst=[1,2,2,2,3,3,4,4,5,6]
from collections import Counter
Counter(lst).most_common(1)[0]
Counter(lst) returns a dict of element-occurence pairs. most_common(n) returns the n most common elements from the dict, along with the number of occurences.