Python: match lists in two lists of lists - python

I have two lists of lists. The first is composed of lists formatted as follows:
listInA = [id, a1, a2, a3]
The second is composed of lists formatted similarly, with the id first:
listInB = [id, b1, b2, b3]
Neither list is sorted, and they are not of equal lengths. What is the best way to make a list of lists, with each list of the format:
listInC = [id, a1, a2, a3, b1, b2, b3]
where the id's are matched between both lists? Thanks!

You can create a dictionary using dict comprehension from the second list of lists from ID to list. Then, create your new list using list comprehension, appending the list based on IDs.
listA = [
[1, 'a', 'b', 'c'],
[2, 'd', 'e', 'f'],
]
listB = [
[2, 'u', 'v', 'w'],
[1, 'x', 'y', 'z'],
]
b_map = {b[0]: b for b in listB}
print([a + b_map[a[0]][1:] for a in listA])
Output:
[
[1, 'a', 'b', 'c', 'x', 'y', 'z'],
[2, 'd', 'e', 'f', 'u', 'v', 'w']
]

The fact that the lists are not sorted and are not of equal length increases the difficulty of coming up with an efficient solution to the problem. However, a quick and dirty solution that would work in the end is definitely still feasible.
The ID seems to be first in both lists. Since this is the case, then for each list a in A, we can get the first element of a and check the lists b in B. If the first elements match, then we can create a list including the remaining elements of a and b and append that to C. In short...
def foo(A, B):
C = []
for a in A:
aID = a[0]
for b in B:
if aID == b[0]:
c = [aID, a[1], a[2], a[3], b[1], b[2], b[3]]
C.append(c)
return C
When dealing with large list sizes for A and B, the efficiency of this solution would drop abysmally, but it should work for reasonably-sized lists.

Related

Extract non-repeated lists from a list of lists based on a criteria on a common element in all lists

Is there any way to extract non-repeated lists from a list of lists based on a criteria on a common element in all lists? For example if I have the following list of list:
list_lists = [['a', [1,2]], ['b', [2,5]], ['c', [1,2]], ['d', [2,5]], ['e', [2,6]]]
Let's assume that my criteria to call a list unique is the last element in that list. So, since [2,6] is repeated once then ['e', [2,6]] is the only element that is unique and I can say:
list_of_unique = [['e', [2,6]]]
Naive solution that firstly comes to mind
list_lists = [['a', [1,2]], ['b', [2,5]], ['c', [1,2]], ['d', [2,5]], ['e', [2,6]]]
counter = {}
for i in range(len(list_lists)):
last = tuple(list_lists[i][-1])
if last not in counter:
counter[last] = 1, i
else:
counter[last] = counter[last][0] + 1, i
print([list_lists[i] for c, i in counter.values() if c == 1])

Subtract 2 lists by duplicate elements in python

Hello I want to know how to subtract 2 lists by duplicate elements, not by value, in python.
ListA = [G, A, H, I, J, B]
ListB = [A, B, C]
ListC = [G, H, I, J]
So we subtract the ListB values, if they are found in ListA as duplicates, and the ListC will give back the non-duplicate values in ListA.
Mathematically written it would be:
ListC = ListA - (ListA ∩ ListB)
(I don't want to remove the duplicates in ListA, only the intersection between ListA and ListB, as described in the above formula, so this question is not a duplicate of questions/48242432
You can do a list comprehension..
[x for x in listA if x not in listB]
Try this
>>> def li(li1,li2):
li3=li1
for i in li2:
if i in li1:
li3.remove(i)
return(li3)
>>> li(["G","A","H","I","J","B"],["A","B","C"])
['G', 'H', 'I', 'J']
Use the sets library in Python.
from sets import Set
setA = Set(['G', 'A', 'H', 'I', 'J', 'B'])
setB = Set(['A', 'B', 'C'])
# get difference between setA and intersection of setA and setB
setC = setA - (setA & setB)
The cool thing about sets is that they tend to operate faster than list comprehensions. For instance, this operation would tend to run at O(len(setA)) + O(min(len(setA), len(setB))) = O(len(setA)) whereas a list comprehension would run at O(len(setA) * len(setB)) to achieve the same result. Of course, these are average cases not worst cases. Worst case, they'd be the same. Either way, you should use the object that best fits your operations, right?
See the Python documentation for more.
This is what you want?
L1 = ['A', 'G', 'H', 'I', 'J', 'B']
L2 = ['A', 'B', 'C']
for i in L1:
if i not in L2:
print(i)
On basis of using mathematical set notations, why not use sets?
ListA = [G,A,H,I,J,B]
ListB = [A,B,C]
SetC = set(ListA) - set(ListB)
But then you get sets out and have to go back to lists... also the order might change and any character that was twice in the list is then only once in it
https://docs.python.org/3/tutorial/datastructures.html#sets
>>> a = set('abracadabra') # sets have only unique elements and are unordered
>>> b = set('alacazam')
>>> a # unique letters in a
{'a', 'r', 'b', 'c', 'd'}
>>> a - b # letters in a but not in b
{'r', 'd', 'b'}
>>> a | b # letters in a or b or both
{'a', 'c', 'r', 'd', 'b', 'm', 'z', 'l'}
>>> a & b # letters in both a and b
{'a', 'c'}
>>> a ^ b # letters in a or b but not both
{'r', 'd', 'b', 'm', 'z', 'l'}
list1 = ['string1','string2','string3']
list2 = ['string1','string2','string3','pussywagon']
newList = list(set(list2)-set(list1))
# output
print(newList)
# type
print(type(newList))
test code

zip the values from a dictionary [duplicate]

This question already has an answer here:
zip two values from the dictionary in Python
(1 answer)
Closed 6 years ago.
I have a dictionary in python 2.7 that has the following structure:
x = {
'1': ['a', 'b', 'c'],
'2': ['d', 'e', 'f']
}
The length of the value list is always the same and I would like to basically zip the value lists with corresponding values. So, in this case it will create three new lists as:
[['a', 'd'], ['b', 'e'], ['c', 'f']]
I know I can write an awful looking loop to do this but I was wondering if there is a more pythonic way to do this. I need to preserve the order.
You can do the following:
zip(*x.values())
Explanation:
x.values() returns [['a', 'b', 'c'], ['d', 'e', 'f']] (order may change so you might need to sort x first.)
zip([a, b], [c, d]) returns [[a, c], [b, d]]
To expand x.values() into arguments to zip, prepend * to it.
This is single line solves the problem but is likely worse looking than your loop. It loops over the sorted keys and produces a list to pass to zip and then maps over the result converting the tuples into lists.
>>> x = {'1': ['a', 'b', 'c'], '2': ['d', 'e', 'f']}
>>> map(list, zip(*[x[k] for k in sorted(x)]))
[['a', 'd'], ['b', 'e'], ['c', 'f']]
res = list(zip(x['1'], x['2']))
res = list(map(list, res))
An explanation:
zip(x['1'], x['2'])
Creates a zip object that links up your pairs.
res = list(zip(x['1'], x['2']))
That zip object now become a list of tuples.
list(map(list, res))
For each element in res (each tuple), change the data structure from tuple to list, as you requested in your desired output above (map the list data type onto all elements in res). Then, convert that map object into a list to arrive at the final, desired result.

Python: How to create new list with certain alphabetized items from original list?

Suppose list1 is [a, y, k, x, d, l]
How do I make a new list containing the first two and last two alphabetically (a, d, and x, y)?
You can use sorted to sort the original list, then use list slicing to get the first two and last two elements of the sorted list.
>>> list1 = ['a', 'y', 'k', 'x', 'd', 'l']
>>> sorted_list = sorted(list1)
>>> new_list = sorted_list[0:2] + sorted_list[-2:]
>>> new_list
['a', 'd', 'x', 'y']

Fast way to find lists contains two particular items?

I have a list of lists (about 200) contains different strings:
lists = [
['a', 'b', 'c', 'g', ...],
['b', 'c', 'f', 'a', ...],
...
]
now I'd like to find out all the lists that contains two given strings, in the given order.
for example, given ('a', 'g'), ['a', 'b', 'c', 'g', ...] will be matched.
what's the pythonic way of doing this?
In my opinion the most Pythonic way would be:
selection = [L for L in lists
if x1 in L and x2 in L and L.index(x1) < L.index(x2)]
the defect is that it will search each element twice, first to check the presence (forgetting the index) and second to check the ordering.
An alternative could be
def match(a, b, L):
try:
return L.index(a) < L.index(b)
except ValueError:
return False
selection = [L for L in lists if match(x1, x2, L)]
but I find it slightly uglier and I wouldn't use it unless performance is a problem.
If the logic required instead is to accept a list containing [... x2 ... x1 ... x2 ...] then the check is different:
selection = [L for L in lists
if x1 in L and x2 in L[L.index(x1)+1:]]
that translated to english as "if x1 is in the list and x2 is the part following first x1" that also works as expected if x1 and x2 are the same value.

Categories

Resources