Merge items from separate lists into nested lists - python-3.x

Hello I am trying to merge two lists sequentially into sub lists. I wonder if this is possible without list comprehensions or a lambda operation as I'm still learning how to work with those approaches. Thank you
a = [0,1,2,3]
b = [4,5,6,7]
#desired output
c = [0,4],[1,5],[2,6],[3,7]

An approach that doesn't involve lambdas or list comprehensions (not sure what the issue is with list-comps) would be with map:
c = list(map(list, zip(a, b)))
This first zips the lists together, then creates a list instance for every tuple generated from zip with map and wraps it all up in list in order for map to yield all it's contents:
print(c)
[[0, 4], [1, 5], [2, 6], [3, 7]]
This, at least in my view, is less understandable than the equivalent comprehension John supplied in a comment.

Here’s a solution suitable for beginners!
c = []
a = [0,1,2,3]
b = [4,5,6,7]
for i in range(min(len(a), len(b))):
c.append([a[i], b[i]]) # writing [a[i], b[i]] creates a new list
print(c)

Related

How to find match between two 2D lists in Python?

Lets say I have two 2D lists like this:
list1 = [ ['A', 5], ['X', 7], ['P', 3]]
list2 = [ ['B', 9], ['C', 5], ['A', 3]]
I want to compare these two lists and find where the 2nd item matches between the two lists e.g here we can see that numbers 5 and 3 appear in both lists. The first item is actually not relevant in comparison.
How do I compare the lists and copy those values that appear in 2nd column of both lists? Using 'x in list' does not work since these are 2D lists. Do I create another copy of the lists with just the 2nd column copied across?
It is possible that this can be done using list comprehension but I am not sure about it so far.
There might be a duplicate for this but I have not found it yet.
The pursuit of one-liners is a futile exercise. They aren't always more efficient than the regular loopy way, and almost always less readable when you're writing anything more complicated than one or two nested loops. So let's get a multi-line solution first. Once we have a working solution, we can try to convert it to a one-liner.
Now the solution you shared in the comments works, but it doesn't handle duplicate elements and also is O(n^2) because it contains a nested loop. https://wiki.python.org/moin/TimeComplexity
list_common = [x[1] for x in list1 for y in list2 if x[1] == y[1]]
A few key things to remember:
A single loop O(n) is better than a nested loop O(n^2).
Membership lookup in a set O(1) is much quicker than lookup in a list O(n).
Sets also get rid of duplicates for you.
Python includes set operations like union, intersection, etc.
Let's code something using these points:
# Create a set containing all numbers from list1
set1 = set(x[1] for x in list1)
# Create a set containing all numbers from list2
set2 = set(x[1] for x in list2)
# Intersection contains numbers in both sets
intersection = set1.intersection(set2)
# If you want, convert this to a list
list_common = list(intersection)
Now, to convert this to a one-liner:
list_common = list(set(x[1] for x in list1).intersection(x[1] for x in list2))
We don't need to explicitly convert x[1] for x in list2 to a set because the set.intersection() function takes generator expressions and internally handles the conversion to a set.
This gives you the result in O(n) time, and also gets rid of duplicates in the process.

Combining 2 lists with streams in Groovy

Say I have two lists of equal size [1, 2, 3, 4, ...] and [a, b, c, d, ...]. Is there a way I make a map with streams that maps 1 to a, 2 to b, 3 to c, and so on without using lambda functions or nested functions?
I would use map and pass in a function, but this passed-in function can only take 1 argument and I need both pieces of information to map the elements to each other.
IntStream(1, list1.size()).stream().map(this.&combineListsFunction).collect...
combineListsFunction can only use the information from the stream, but I need both lists for the function to work.
You can transpose both lists (which will give you a list of tuples and then create the map from it with collectEntries() (which takes exactly this). E.g.:
def l1 = [1,2,3]
def l2 = ["a","b","c"]
assert [(1): "a", (2): "b", (3): "c"] == [l1,l2].transpose().collectEntries()

Python list comprehension - conditional for-loop

I've written some code like so which works fine and does what I want:
#!/usr/bin/env python3
myList = [[0], [1, 2], {'val': [3, 4, 5]}, [6]]
flat1 = []
for sublist in myList:
if type(sublist) is list:
for item in sublist:
flat1.append(item)
else:
for item in sublist['val']:
flat1.append(item)
print(flat1)
So it's a twist on the standard nested list flattening. The twist is that some nested items are not actually lists, but rather dictionaries with a 'val' (and we want the items in the 'val' list in those cases).
I'm trying to make it into a list comprehension. Here is what I've tried:
flat2 = [item for sublist in myList for item in sublist if type(sublist) is list else for item in sublist['val']]
print(flat2)
I get the following error with a caret pointing to the 'else'.
SyntaxError: invalid syntax
And yes what I've written into the list comprehension seems like nonsense and no doubt the compiler has no idea what I'm trying to do.
Is it possible to do what I'm trying to do with a list comprehension?
[item
for sublist in myList
for item in (sublist if type(sublist) is list else sublist['val'])
]
First off, I recommend against this approach. Why do you want to take what is already pretty readable and condense it so that it's unreadable?
flattened = [i for iterable in
(j if type(j) is list else j["val"] for j in myList)
for i in iterable]
Update after reading comment
One nice thing to do is to break out the list comprehension into two steps:
iterables = (j if type(j) is list else j["val"] for j in myList)
flattened = [i for iterable in iterables for i in iterable]
This is more readable -- and no less computationally efficient. Note the use of parentheses in iterables -- which makes it a generator that is lazily evaluated. That way, if myList is really long, you're still only reading through it once and you don't have to wait to read all the way through before proceeding.

How to get a second element of every element in a list

Imagine a python list
a=[[1,2],[3,4],[5,6]]
how could I get a list out of this such that I get the elements of the list a that satisfy that the second element is bigger than 2?
In [32]: a=[[1,2],[3,4],[5,6]]
In [33]: [s for s in a if s[1]>2]
Out[33]: [[3, 4], [5, 6]]
So I guess the result you expect with your example is:
result=[[3,4], [5,6]]
In that case you'd just need to do:
result=[l for l in a if l[1]>2]
This is called list comprehension.

how do you check if element is already in the list through comprehension?

How do you check whether an element is already in the list when I am doing it in comprehension?
For example say in following comprehension I want to restrict duplicate numbers Though I am not looking for unique number at all, I want to prevent via an if condition.
[x for x in [1,2,3,1,2,3]]
I am looking for something like
[x for x in [1,2,3,1,2,3] if not in self]
I think what you are looking for is set comprehension and conversion to list. It would do what you want without any odd syntax.
ans = list({x for x in [1,2,3,1,2,3])})
Actaully that can be also be simplified to
ans = list(set([1,2,3,1,2,3]))
but I think the first one might be better in performance.
You can't access the comprehension as you're creating it (as far as I know; someone please correct me if I'm wrong!), but in your case you can just use a set, which eliminates duplicates.
uniques = set([1, 2, 3, 1, 2, 3])
print(uniques) # >>> set([1, 2, 3])
If your list comprehension needs to be more complex, you can index the comprehension from the set, rather than the original list.
mylist = [1, 2, 3, 1, 2, 3]
print([x*x for x in set(mylist)]) # >>> [1, 4, 9]
If you really need direct access to the list during creation, you need to use an explicit loop rather than a comprehension.
x = [1,2,3,1,2,3]
y = [x[n] for n in range(len(x)) if x.index(x[n]) == n]
?
I think at this point, it's probably more readable to simply write it using a for-loop rather than a comprehension.

Resources