Ovechkin250
Ovechkin250

Reputation: 51

How to do this specific list comprehension in Python?

points = [
    [[x,y], [x,y], [x,y]],
    [[x,y], [x,y], [x,y], [x,y], [x,y]],
    [[x,y]]
]

weights = [1, 2, 3]

output  = [
    [[x,y,1], [x,y,1], [x,y,1]],
    [[x,y,2], [x,y,2], [x,y,2], [x,y,2], [x,y,2]],   
    [[x,y,3]]
]

I want to combine Points and Weights to ultimately look like the output column. The length of points and weights will always be the same. However, the amount of [x,y] pairs will differ for each list inside the list. Exactly how I have shown the example. Python is the language I am using.

Any help would be greatly appreciated

Upvotes: 1

Views: 122

Answers (3)

Karl Knechtel
Karl Knechtel

Reputation: 61643

Work from the inside out.

On the inside, we have [[x, y], [x, y], [x, y]] and 1, and we want to produce [[x, y, 1], [x, y, 1], [x, y, 1]].

So, we are appending 1 to each of the [x, y] values. But .append modifies a value in-place and returns None; to do work with list-comprehensions, we want to return new values. So we can instead create [1] from the input 1, and concatenate lists with +.

Therefore, we want the given inner item, + an appended list [1], for each of the items that is found in our original data ([[x, y], [x, y], [x, y]]). Since we are going to apply this to nested lists, let's say that we refer to that list as a row. Then, we write the list comprehension, describing that task - exactly as I put it, reading left to right: [item + [1] for item in row].

(Edit: as noted in the other answer, it also works to take advantage of unpacking: instead of item + [1], we can do [*item, 1].)

Now: that is the sort of processing that we want to do to each row. But we want to use a different value instead of the 1 each time. Those values come from weights, which we want to iterate in parallel with the rows of the overall points.

So, we need to use zip in order to pair up each weight of the weights with a corresponding row from points. That looks like zip(points, weights), and when we iterate over that, we get (row, weight) pairs.

Our processing for a given row now looks like [item + [weight] for item in row], after modifying it to account for the varying weight.

So we apply the technique again: we want to do [item + [weight] for item in row], for each of the (row, weight) pairs (parentheses are not strictly necessary here, but make things a lot easier to understand) that are found in our zipped lists of points and weights. And again, we read that left to right:

[[item + [weight] for item in row] for (row, weight) in zip(points, weights)]

Upvotes: 2

Akshay Sehgal
Akshay Sehgal

Reputation: 19307

Try this one-liner list comprehension without using a zip -

[[k+[weights[i]] for k in j] for i,j in enumerate(points)]

Upvotes: 0

orlp
orlp

Reputation: 117846

Using zip it's relatively easy:

[[p+[w] for p in pl] for pl, w in zip(points, weights)]

Upvotes: 4

Related Questions