list of list multiplication with list - python

I want to multiply a list of list with a list using python 3 suppose that the list of list is of name L as follows:
L = [[45.909221207388235, 84.41069326628269], [80.6591435966521, 47.93257841035172]]
and the second list is:
S = [0.002, 0.001]
the multiplication should be: L[0][0]* S[0] and L[0][1]* S[0] then L[1][0]* S[1] and L[1][1]* S[1].
I tried the zip method :
[a*b for x,y in zip(S,L) for a,b in zip(x,y)]
But an error appears: zip argument 1 must support iteration.
the second trial was using map(lambda):
map(lambda x,y:x*y,L,S)
but the obtained results were wrong:
[9.181844241477647e-05, 0.00016882138653256538, 0.0001613182871933042, 9.586515682070343e-05]
the correct values are:
[0.09181844241477648, 0.1688213865325654, 0.0806591435966521, 0.047932578410351714]

You want to use zip, but not twice:
>>> L = [[45.909221207388235, 84.41069326628269], [80.6591435966521, 47.93257841035172]]
>>> S = [0.002, 0.001]
>>> [n*x for n, sub in zip(S, L) for x in sub]
[0.09181844241477648, 0.1688213865325654, 0.0806591435966521, 0.047932578410351714]
>>>
So, you want to pair up every number with every sublist, then multiply every number in the sublist by that main number.
Note, just in case you are using numpy (I don't think you are, and I don't think it would be reasonable to use numpy just for this), and S and L are numpy.ndarray objects, i.e.:
>>> S = np.array(S)
>>> L = np.array(L)
Then you probably just want:
>>> (S*L).ravel()
array([0.09181844, 0.08441069, 0.16131829, 0.04793258])

If I understand corresly you want to multiply each column in L by the corresponding value of S:
L = [[45.909221207388235, 84.41069326628269],
[80.6591435966521, 47.93257841035172]]
S = [0.002, 0.001]
R = [ [s*n for n in row] for s,row in zip(S,L) ]
output:
print(R)
[ [0.09181844241477648, 0.1688213865325654],
[0.0806591435966521, 0.047932578410351714]]
You should have given an example with a different number of rows than columns to make this clearer

Related

Replace consecutive numbers in list with their min

I have a list of integers and some of them are consecutive. I would like to either replace the consecutive ones with their group's minimum or delete all of them except each group's minimum. Example:
my_list = [1,2,3,4,6,7,8,9,11]
result = [1,1,1,1,6,6,6,6,11]
or even deleting them like so:
result = [1,6,11]
For the second way,
print([x for x in my_list if x-1 not in my_list])
gives you the list of all numbers for which the previous is not in the original list
Simple solution:
>>> from itertools import pairwise
>>> result = [lst[0]]
>>> for i, j in pairwise(lst):
... if j - i != 1:
... result.append(j)
...
>>> result
[1, 6, 11]
Note: itertools.pairwise was introduced in Python 3.10. If you are using an earlier version, you can consider implementing pairwise yourself or simply using indexes.

Is there a Don't Care value for lists in Python

Is there a way to use count() where you are looking for a specific value in the nested list and not caring about the rest?
lst = [[1,6],[1,4],[3,4],[1,2]]
X = 1
lst.count([X, _ ])
This would return a count of 3, since there are three nested lists that have a 1 in the first index.
Is there a way to do this?
Use some sneaky sum() hacks:
sum(k[0] == X for k in your_list)
I.e.
>>> X = 1
>>> your_list = [[1,6],[1,4],[3,4],[1,2]]
>>> sum(k[0] == X for k in your_list)
3
why?
The section: k[0] == X for k in your_list is a generator expression that yields True for each element in your_list which has first element equal to your X. The sum() function takes the values and treats a True as a 1.
Look at the length of a filtered list:
my_list = [[1,6][1,4][3,4][1,2]]
X = 1
len([q for q in my_list if q[0] == X])
Or, if you prefer to use count, then make a list of the items you do care about:
[q[0] for q in my_list].count(X)
You can do len(filter(lambda x: x[0] == 1, lst))
But be careful, if your list contains an element that is not a list (or an empty list) it will throw an exception! This could be handled by adding two additional conditions
len(filter(lambda x: type(x) == list and len(x) > 0 and x[0] == 1, lst))
Counting how often one value occurs in the first position requires a full pass over the list, so if you plan to use the potential countfunction(inputlist, target) more than once on the same list, it's more efficient to build a dictionary holding all the counts (also requiring one pass) which you can subsequently query with O(1).
>>> from collections import Counter
>>> from operator import itemgetter
>>>
>>> lst = [[1,6],[1,4],[3,4],[1,2]]
>>> c = Counter(map(itemgetter(0), lst))
>>> c[1]
3
>>> c[3]
1
>>> c[512]
0
Others have shown good ways to approach this problem using python built-ins, but you can use numpy if what you're actually after is fancy indexing.
For example:
import numpy as np
lst = np.array([[1,6],[1,4],[3,4],[1,2]])
print(lst)
#array([[1, 6],
# [1, 4],
# [3, 4],
# [1, 2]])
In this case lst is a numpy.ndarray with shape (4,2) (4 rows and 2 columns). If you want to count the number of rows where the first column (index 0) is equal to X, you can write:
X = 1
print((lst[:,0] == X).sum())
#3
The first part lst[:,0] means grab all rows and only the first index.
print(lst[:,0])
#[1 1 3 1]
Then you check which of these is equal to X:
print(lst[:,0]==X)
#[ True True False True]
Finally sum the resultant array to get the count. (There is an implicit conversion from bool to int for the sum.)

Filtering a list of two-element sublists with a list comprehension

I have a list of lists
input = [[2,13],[5,3],[10,8],[13,4],[15,0],[17,10],[20,5],[25,9],[28,7],[31,0]]
I want to write a list comprehension where for the [a,b] pairs above I get the pairs where b > a. In the above example that would be [2,13].
My attempt
x = [[item[i],[j]] for item in inputArray if j>i]
produces a NameError
NameError: name 'j' is not defined`
The problem with your attempt is that you never tell Python what i and j are supposed to be. The check j > i cannot be computed and the list [item[i],[j]] can't be built without that information.
You can issue
>>> inp = [[2,13],[5,3],[10,8],[13,4],[15,0],[17,10],[20,5],[25,9],[28,7],[31,0]]
>>> [[a, b] for a, b in inp if b > a]
[[2, 13]]
This solution does not produce a NameError because for a, b in inp tells Python to iterate over the elements of inp (two-element sublists) and in each iteration assign the name a to the first element of a sublist and the name b to the second element.
I used the name inp instead of input because the latter is already taken by a builtin function for getting user input.
Explanation of the list comprehension
The comprehension is equivalent to
>>> result = []
>>> for a, b in inp:
... if b > a:
... result.append([a, b])
...
>>> result
[[2, 13]]
Every two-element list in inp is unpacked into the variables a and b. If the filter condition b > a is True, then a list [a, b] is built and included in the final result.
If you don't want to use unpacking, you can also index into the sublists of inp like this:
>>> [sub[:] for sub in inp if sub[1] > sub[0]]
[[2, 13]]
Taking a full slice of sub via sub[:] ensures that like in the other solutions presented so far, the filtered result stores (shallow) copies of the sublists of inp. If copying it not necessary, you can omit the [:].
This code does not produce a NameError because for sub in inp tells Python to iterate over inp and in each iteration assign the name sub to the next sublist. In addition, explicit numbers (0 and 1) are used for the indices.
Personally, I prefer the solution with unpacking. It is easier to read and will run even if the elements of inp don't support indexing, but are iterables from which two elements can be extracted.
You should unpack each pair into the i, j variables, and then you can compare them:
x = [[i, j] for i,j in inputList if j > i]
(note I have renamed inputArray, inputList)
Or without unpacking:
x = [item for item in inputList if item[1] > item[0]]

How can I check if a list of nodes have already been included in a list within a list of lists?

I have the following list: a = [[1,2,3],[4,5,6],[7,8,9]] which contains 3 lists, each being a list of nodes of a graph.
I am also given a tuple of nodes z = ([1,2], [4,9]). Now, I will like to check if either of the lists in z has been included in a list in a. For example, [1,2] is in [1,2,3], in a, but [4,9] is not in [4,5,6], although there is an overlapping node.
Remark: To clarify, I am also checking for sub-list of a list, or whether every item in a list is in another list. For example, I consider [1,3] to be "in" [1,2,3].
How can I do this? I tried implementing something similar found at Python 3 How to check if a value is already in a list in a list, but I have reached a mental deadlock..
Some insight on this issue will be great!
You can use any and all:
a = [[1,2,3],[4,5,6],[7,8,9]]
z = ([1,2], [4,9])
results = [i for i in z if any(all(c in b for c in i) for b in a)]
Output:
[[1, 2]]
You can use sets to compare if the nodes appear in a, <= operator for sets is equivalent to issubset().
itertools module provides some useful functions, itertools.product() is equivalent to nested for loops.
E.g.:
In []:
import itertools as it
[m for m, n in it.product(z, a) if set(m) <= set(n)]
Out[]:
[[1, 2]]
a = [[1,2,3],[4,5,6],[7,8,9]]
z = ([1,2], [4,9])
for z_ in z:
for a_ in a:
if set(z_).issubset(a_):
print(z_)
itertools.product is your friend (no installation builtin python module):
from itertools import product
print([i for i in z if any(tuple(i) in list(product(l,[len(i)])) for l in a)])
Output:
[[1, 2]]
Since you're only looking to test the sub-lists as if they were subsets, you can convert the sub-lists to sets and then use set.issubset() for the test:
s = map(set, a)
print([l for l in z for i in s if set(l).issubset(i)])
This outputs:
[[1, 2]]

Finding indices of items from a list in another list even if they repeat

This answer works very well for finding indices of items from a list in another list, but the problem with it is, it only gives them once. However, I would like my list of indices to have the same length as the searched for list.
Here is an example:
thelist = ['A','B','C','D','E'] # the list whose indices I want
Mylist = ['B','C','B','E'] # my list of values that I am searching in the other list
ilist = [i for i, x in enumerate(thelist) if any(thing in x for thing in Mylist)]
With this solution, ilist = [1,2,4] but what I want is ilist = [1,2,1,4] so that len(ilist) = len(Mylist). It leaves out the index that has already been found, but if my items repeat in the list, it will not give me the duplicates.
thelist = ['A','B','C','D','E']
Mylist = ['B','C','B','E']
ilist = [thelist.index(x) for x in Mylist]
print(ilist) # [1, 2, 1, 4]
Basically, "for each element of Mylist, get its position in thelist."
This assumes that every element in Mylist exists in thelist. If the element occurs in thelist more than once, it takes the first location.
UPDATE
For substrings:
thelist = ['A','boB','C','D','E']
Mylist = ['B','C','B','E']
ilist = [next(i for i, y in enumerate(thelist) if x in y) for x in Mylist]
print(ilist) # [1, 2, 1, 4]
UPDATE 2
Here's a version that does substrings in the other direction using the example in the comments below:
thelist = ['A','B','C','D','E']
Mylist = ['Boo','Cup','Bee','Eerr','Cool','Aah']
ilist = [next(i for i, y in enumerate(thelist) if y in x) for x in Mylist]
print(ilist) # [1, 2, 1, 4, 2, 0]
Below code would work
ilist = [ theList.index(i) for i in MyList ]
Make a reverse lookup from strings to indices:
string_indices = {c: i for i, c in enumerate(thelist)}
ilist = [string_indices[c] for c in Mylist]
This avoids the quadratic behaviour of repeated .index() lookups.
If you data can be implicitly converted to ndarray, as your example implies, you could use numpy_indexed (disclaimer: I am its author), to perform this kind of operation in an efficient (fully vectorized and NlogN) manner.
import numpy_indexed as npi
ilist = npi.indices(thelist, Mylist)
npi.indices is essentially the array-generalization of list.index. Also, it has a kwarg to give you control over how to deal with missing values and such.

Categories