Python List comprehension when item index is required - python

I am attempting to write the corresponding list comprehension for the following code snippet.
# Initialize data.
queryRelDict = {'1': [1, 2, 3],
'2': [4, 5, 6],
'3': [11, 13, 14]}
related_docs_indices = [1, 2, 3, 4, 5, 6, 7, 8, 12, 13, 14]
relOrNot = [0] * k
for item in queryRelDict.keys():
for i in range(len(related_docs_indices)):
if related_docs_indices[i] + 1 in queryRelDict[item]:
relOrNot[i] = 1
Basically I have a dictionary, where each key has a list as its value. Now my list relOrNot[i] needs to be 1, if ith element of related_docs_indices is in either of the lists in the dictionary.
The desired Output is:
[1, 1, 1, 1, 1, 1, 0, 0, 0, 1, 1]
I tried the following two variations, but is not able to get the desired output.
relOrNot2 = [1 for item in queryRelDict.keys() for i in range(len(related_docs_indices)) if related_docs_indices[i] + 1 in queryRelDict[item]]
but the output is
[1, 1, 1, 1, 1, 1, 1, 1, 1, 1]
I also tried
relOrNot2 = [1 if related_docs_indices[i] + 1 in queryRelDict[item] else 0 for item in queryRelDict.keys() for i in range(len(related_docs_indices))]
Corresponding Output:
[0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0]
What modification is necessary to get the desired output?

Here if you want an one-liner :)
relOrNot = [1 if v in set().union(*queryRelDict.values()) else 0 for v in related_docs_indices]

If your desired output is a list relOrNot, where relOrNot[i] is 1, if ith element of related_docs_indices is in either of the lists in the dictionary queryRelDict (then it must have the same length as related_docs_indices), then you can do the following:
# first create one flat list with all elements of the sublists in the dictionary
flatlist = [i for sublist in queryRelDict.itervalues() for i in sublist]
relOrNot = [1 if i in flatlist else 0 for i in related_docs_indices]
# [1, 1, 1, 1, 1, 1, 0, 0, 0, 1, 1]

For each key, you are iterating through the related_doc_indices and checking if there is a matching value within the set of values for that key. For key '1', it would look like this:
key 1 values = [1, 2, 3]
related_docs_indices = [
1, # 1 (match)
2, # 1 (match)
3, # 1 (match)
4, # 0 (no match)
5, # 0 (no match)
6, # 0 (no match)
7, # 0 (no match)
8, # 0 (no match)
12, # 0 (no match)
13, # 0 (no match)
14] # 0 (no match)
The desired output for this key should thus be:
[1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0]
One issue that you have is that keys are unordered in dictionaries, so that results of the longer list can vary depending on the random order of the keys. For example:
>>> queryRelDict.keys()
['1', '3', '2']
Let's say you first sort the keys, then I believe the desired output should look like this:
[1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, # key '1'
0, 0, 0, 1, 1, 1, 0, 0, 0, 0, 0, # key '2'
0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1] # key '3'
keys = queryRelDict.keys()
keys.sort()
>>> [1 if i in queryRelDict.get(item) else 0
for item in keys for i in related_docs_indices]
#[1, 2, 3, 4, 5, 6, 7, 8, 12, 13, 14] related_doc_indices
[1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, # key '1' values: [1, 2, 3]
0, 0, 0, 1, 1, 1, 0, 0, 0, 0, 0, # key '2' values: [4, 5, 6]
0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1] # key '3' values: [11, 13, 14] (note 11 is not in related_doc_indices)

Create a set with all keys and all values and in your loop just look if the required value is in the set.
s = set()
for (k,v) in queryRelDict.items():
s.add(int(k))# because your keys are string
s = s | set(v)
map(lambda x:1 if x in s else 0, related_docs_indices)
=>[1, 1, 1, 1, 1, 1, 0, 0, 0, 1, 1]

Related

Is there a function I can use in Python to randomly select elements equal to specified number and change it to another?

For instance, if I have the following distribution, I want to randomly select 4 elements = 1 and change that element to = 0.
lst = [1, 0, 0, 1, 0, 1, 1, 1, 0, 1, 0, 1, 0, 1, 0, 1, 1, 0]
-> Function <-
lst = [0, 0, 0, 1, 0, 1, 1, 0, 0, 0, 0, 0, 0, 1, 0, 1, 1, 0]
or
lst = [1, 0, 0, 1, 0, 1, 1, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0]
or
lst = [0, 0, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 0, 0, 0]
or ....
Using numpy:
ones = np.where(lst)[0]
to_zero = np.random.choice(ones, 4, replace=False)
for i in to_zero: # Alternatively, if lst is an array: lst[to_zero] = 0
lst[i] = 0
To achieve what you want, you first need to get the list of the indexes of the one elements. Then you need to pick 4 random indexes and update the values from the starting list.
Note that you cannot use the random.choices method because it doesn’t return unique values, use random.sample instead.
def update_randomly(tab):
n = range(len(tab))
one_indexes = [i for i in n if tab[i] == 1]
rdm_indexes = random.sample(one_indexes, 4)
return [0 if i in rdm_indexes else tab[i] for i in n]

Change zeros into their closest left nonzero neighbors in an array

Assuming I have an array :
[1, 0, 0, 2, 0, 0, 0, 0, 3, 0, 0, 0, 4, 0, 0, 1, 0, 0, 0, 2]
How can I change the zeros into the value of its closest left non-zero neighbor?
[1, 1, 1, 2, 2, 2, 2, 2, 3, 3, 3, 3, 4, 4, 4, 1, 1, 1, 1, 2]
l=[1, 0, 0, 2, 0, 0, 0, 0, 3, 0, 0, 0, 4, 0, 0, 1, 0, 0, 0, 2]
arr=[]
for i in l:
if i!=0:
arr.append(i)
left_element=i
else:
arr.append(left_element)
print(arr)
keep track of non zero left element and append it to the new list
Space:-O(n)
runtime:-O(n)
OR
l=[1, 0, 0, 2, 0, 0, 0, 0, 3, 0, 0, 0, 4, 0, 0, 1, 0, 0, 0, 2]
for i in range(len(l)):
if l[i]!=0:
left_element=l[i]
else:
l[i]=left_element
print(l)
I would iterate through your array and evaluate each item, replacing when necessary:
arr = [1, 0, 0, 2, 0, 0, 0, 0, 3, 0, 0, 0, 4, 0, 0, 1, 0, 0, 0, 2]
# replace values with the following
previous_x = None
for i,x in enumerate(arr):
if x>0:
previous_x = x
else:
arr[i] = previous_x
If your array is massive (>100,000), I would look into leveraging numpy for a solution.

How do I remove the extra zero in the end of each line of the output?

This code generates a pascal triangle:
import pprint
def nextRow(cRow):
cRow.append(0)
return [cRow[m - 1] + cRow[m + 1] for m in range(len(cRow) - 1)]
def Pascal(n):
row = [0, 0, 0, 0, 1, 0, 0, 0, 0]
l = []
for h in range(n):
l.append(row)
row = nextRow(row)
return l
pprint.pprint(Pascal(5))
I am trying to remove the extra zeros without just removing them in the end of the code:
Output:
[[0, 0, 0, 0, 1, 0, 0, 0, 0, 0],
[0, 0, 0, 1, 0, 1, 0, 0, 0, 0],
[0, 0, 1, 0, 2, 0, 1, 0, 0, 0],
[0, 1, 0, 3, 0, 3, 0, 1, 0, 0],
[1, 0, 4, 0, 6, 0, 4, 0, 1, 0]]
Desired Output:
[[0, 0, 0, 0, 1, 0, 0, 0, 0],
[0, 0, 0, 1, 0, 1, 0, 0, 0],
[0, 0, 1, 0, 2, 0, 1, 0, 0],
[0, 1, 0, 3, 0, 3, 0, 1, 0],
[1, 0, 4, 0, 6, 0, 4, 0, 1]]
You can save in l the row calculated without the last element with l.append(row[:-1]) instead of l.append(row) in the Pascal function.
import pprint
def nextRow(cRow):
cRow.append(0)
return [cRow[m - 1] + cRow[m + 1] for m in range(len(cRow) - 1)]
def Pascal(n):
row = [0, 0, 0, 0, 1, 0, 0, 0, 0]
l = []
for h in range(n):
l.append(row[:-1])
row = nextRow(row)
return l
pprint.pprint(Pascal(5))

Tensorflow Initialize list with 0s and 1s similar to tf.one_hot

I currently have a list of values over a time sequence say the values are [1, 3, 5, 7, 3]. Currently I am using tf.one_hot to get a one hot vector/tensor representative for each value within the list.
1 = [0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0]
3 = [0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0]
5 = [0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0]
7 = [0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0]
3 = [0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0]
In Tensorflow is there a way/function that would allow me to do something similar but initialize all values from 0 to the value with 1s?
Desired Result:
1 = [1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0]
3 = [1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0]
5 = [1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0]
7 = [1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0]
3 = [1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0]
You are looking for tf.sequence_mask.
TensorFlow API

how to move all non-zero elements in a python list or numpy array to one side?

I'm going to do the following operation of a list or numpy array:
[0, 0, 0, 1, 0, 0, 4, 2, 0, 7, 0, 0, 0]
move all non-zeros to the right side:
[0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 4, 2, 7]
How can I do this efficiently?
Thanks
============
Sorry I didn't make it clear, I need the order of non-zeros elements remains.
You could sort the list by their boolean value. All falsy values (just zero for numbers) will get pushed to the front of the list. Python's builtin sort appears stable, so other values will keep their relative position.
Example:
>>> a = [0, 0, 0, 1, 0, 0, 5, 2, 0, 7, 0, 0, 0]
>>> sorted(a, key=bool)
[0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 5, 2, 7]
Using NumPy:
>>> a = np.array([0, 0, 0, 1, 0, 0, 4, 2, 0, 7, 0, 0, 0])
>>> np.concatenate((a[a==0], a[a!=0]))
array([0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 4, 2, 7])
You can do this in O(N) time in Python as well by using a simple for-loop. But will take some extra memory which we can prevent in #grc's solution by using a.sort(key=bool):
>>> from collections import deque
#Using a deque
>>> def solve_deque(lst):
d = deque()
append_l = d.appendleft
append_r = d.append
for x in lst:
if x:
append_r(x)
else:
append_l(x)
return list(d) #Convert to list if you want O(1) indexing.
...
#Using simple list
>>> def solve_list(lst):
left = []
right = []
left_a = left.append
right_a = right.append
for x in lst:
if x:
right_a(x)
else:
left_a(x)
left.extend(right)
return left
>>> solve_list([0, 0, 0, 1, 0, 0, 4, 2, 0, 7, 0, 0, 0])
[0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 4, 2, 7]
>>> solve_deque([0, 0, 0, 1, 0, 0, 4, 2, 0, 7, 0, 0, 0])
[0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 4, 2, 7]

Categories