Simultaneously iterate over multiple list and capture difference in values - python

Consider API returning four lists as output. Let's consider output as
a = [1,2,3,4]
b = [1,2,3,4]
c = [1,2,4,3]
d = [1,2,3,5]
Now, first we want to compare these lists are equal or not.
Lists are equal only if elements and there indexes matches.
For example, from above lists, a and b are equal. But a and c are not equal.
If the lists are not equal, then output is expected as: this element at this index in this list is not same as other.
For comparing and getting differences of two lists, I have written below code.
for i in range(len(a)):
if a[i] != c[i]:
print "Expected value at ",i," is ",a[i]
print "But got value ",c[i],"in second list"
Now question is how to achieve this for all four above lists?

You may use zip to iterate over each list simultaneously and compare the value at each index. In the below example, I am comparing the value of list a with remaining lists.
a = [1,2,3,4]
b = [1,2,3,4]
c = [1,2,4,3]
d = [1,2,3,5]
for i, x in enumerate(zip(a, b, c, d)):
print('--------- Index: {}'.format(i))
base = x[0]
for j, y in enumerate(x[1:], 2):
if base!=y:
print('{} not equal to {} : --> List {}'.format(base, y, j))
which prints:
--------- Index: 0
--------- Index: 1
--------- Index: 2
3 not equal to 4 : --> List 3
--------- Index: 3
4 not equal to 3 : --> List 3
4 not equal to 5 : --> List 4

From the comment:
How to find in which list we have different value?
import collections as ct
counter = ct.Counter(map(tuple, [a,b,c,d])) # make hashable keys w/tuples
base = counter.most_common(1)[0][0] # find most frequent sequence
[list(seq) for seq in counter if seq != base] # filter uncommon sequences
Output (the non-matching lists):
[[1, 2, 4, 3], [1, 2, 3, 5]]
We collect all similar sequences as keys in a collections.Counter. If all sequences match, there should only be one entry in the Counter dictionary. Otherwise, filter the remaining sequences.

Set up a list mylist = [a, b, c,d] Then loop through checking which ones are equal and which ones are not equal.
for i in range(len(mylist)-1)
for j in range(i+1, len(mylist))
# Check mylist[i] agaist mylist[j] and report results
For example, this will test a against b, c, and d
b against c and d
c against d

Related

Python: Get item(s) at index list

I am trying to write something that takes a list, and gets the item(s) at an index, either one or multiple.
The example below which I found in another post here works great when I have more than one index. This example doesnt work if b = a single index.
a = [-2,1,5,3,8,5,6]
b = [1,2,5]
c = [ a[i] for i in b]
How do I get this to work with both 1 and multiple index?
Example:
a = [-2,1,5,3,8,5,6]
b = 2
c = [ a[i] for i in b] doesnt work in this case
You can actually check if the type your trying to use for fetching the indices is a list (or a tuple, etc.). Here it is, wrapped into a function:
def find_values(in_list, ind):
# ind is a list of numbers
if isinstance(ind, list):
return [in_list[i] for i in ind]
else:
# ind is a single numer
return [in_list[ind]]
in_list = [-2,1,5,3,8,5,6]
list_of_indices = [1,2,5]
one_index = 3
print(find_values(in_list, list_of_indices))
print(find_values(in_list, one_index))
The function takes the input list and the indices (renamed for clarity - it's best to avoid single letter names). The indices can either be a list or a single number. If isinstance determines your input is a list, it proceeds with a list comprehension. If it's a number - it just treats it as an index. If it is anything else, the program crashes.
This post gives you more details on isinstance and recognizing other iterables, like tuples, or lists and tuples together.
a = [-2, 1, 5, 3, 8, 5, 6]
a2 = [-2]
b = [1, 2, 5]
b2 = [1]
c = [a[i] for i in b]
c2 = [a2[i-1] for i in b2]
The first item of the list is 0, the list with one item is perfectly valid.
Instead of creating a list that manually validates the value of list b in the list a, you could create a separate 3 line code to print out the overlapping intersection of list a and b by this:
a = [-2,1,5,3,8,5,6]
b = [3,4,6]
for i in range(0,len(b)):
if b[i] in a:
print(b[i])
By doing so, you would be able to print out the overlapping intersection even if there were 1 or even no value stored in list b.

Creating list with specified a length and combining other lists

I am trying to generate a list that combines elements of two other lists, one is a value and one is not.
I've tried having two separate lists with and using the join function and append function to combine the two elements together at the certain stage.
To match the length of list d to list a I've used a while loop as a counter.
a=7*[1]
b=[1,2,3,4,5]
c=['a','b','c']
d=[]
The outcome i'm trying to achieve is such that:
list d becomes the length of list a
& is a combination of list b and list c
d=[1a,1b,1c,2a,2b,2c,3a]
Can think of a Naive solution for now
def create(bk, ck, len_required):
dk = []
for bitem in bk:
for citem in ck:
dk.append(str(bitem) + citem)
if len(dk) == len_required:
return dk
len_required = len(a)
b = [1, 2, 3, 4, 5]
c = ['a', 'b', 'c']
d = create(b, c, len_required)
result = [str(b[int(i / len(c)) % len(b)]) + str(c[i % len(c)]) for i in range(len(a))]
This iterates i from 0 to len(a) and concatenates b[int(i / len(c)) % len(b)] and c[i % len(c)] in the output.
You could do it with a list comprehension:
d = [str(v)+L for v in b*len(a) for L in c][:len(a)]
or, if you're allowed to use itertools:
from itertools import cycle
cycleA = cycle(str(v)+L for v in b for L in c)
d = [ next(cycleA) for _ in a ]

Python list check if 2 largest values are the same

In python, is it possible to check if the 2 largest values in a list are the same?
This is my code:
list=[[A, teamAScore], [B, teamBScore], [C, teamCScore], [D, teamDScore]]
list.sort()
print(max(list))
If the largest 2 values are the same, the max function will only return one of them. Is there a way to check if the two last values in the list are the same, so I can compare them in a different way? (Separate function etc etc)
A, B, C and D are Strings. teamAScore etc. are integers
I presume you want the max based on the score i.e the second element so first get the max based on the second element of each sublists scores then keep all sublists that have a score equal to the max:
from operator import itemgetter
lst = [[A, teamAScore], [B, teamBScore], [C, teamCScore], [D, teamDScore]]
# get max of list based on second element of each sublist i.e teamxScore
mx = max(lst,key=litemgetter(1)))
# use a list comp to find all sublists where teamxScore is equal to the max
maxes = [ele for ele in lst if ele[1] == mx[1]]
Demo:
l = [["foo", 2], ["bar", 1], ["foobar", 2]]
mx = max(l, key=itemgetter(1))
maxes = [ele for ele in l if ele[1] == mx[1]]
Output:
[['foo', 2], ['foobar', 2]]
Both foo and foobar had a score equal to the max so we get both sublists returned.

Get list based on occurrences in unknown number of sublists

I'm looking for a way to make a list containing list (a below) into a single list (b below) with 2 conditions:
The order of the new list (b) is based on the number of times the value has occurred in some of the lists in a.
A value can only appear once
Basically turn a into b:
a = [[1,2,3,4], [2,3,4], [4,5,6]]
# value 4 occurs 3 times in list a and gets first position
# value 2 occurs 2 times in list a and get second position and so on...
b = [4,2,3,1,5,6]
I figure one could do this with set and some list magic. But can't get my head around it when a can contain any number of list. The a list is created based on user input (I guess that it can contain between 1 - 20 list with up 200-300 items in each list).
My trying something along the line with [set(l) for l in a] but don't know how to perform set(l) & set(l).... to get all matched items.
Is possible without have a for loop iterating sublist count * items in sublist times?
I think this is probably the closest you're going to get:
from collections import defaultdict
d = defaultdict(int)
for sub in outer:
for val in sub:
d[val] += 1
print sorted(d.keys(), key=lambda k: d[k], reverse = True)
# Output: [4, 2, 3, 1, 5, 6]
There is an off chance that the order of elements that appear an identical number of times may be indeterminate - the output of d.keys() is not ordered.
import itertools
all_items = set(itertools.chain(*a))
b = sorted(all_items, key = lambda y: -sum(x.count(y) for x in a))
Try this -
a = [[1,2,3,4], [2,3,4], [4,5,6]]
s = set()
for l in a:
s.update(l)
print s
#set([1, 2, 3, 4, 5, 6])
b = list(s)
This will add each list to the set, which will give you a unique set of all elements in all the lists. If that is what you are after.
Edit. To preserve the order of elements in the original list, you can't use sets.
a = [[1,2,3,4], [2,3,4], [4,5,6]]
b = []
for l in a:
for i in l:
if not i in b:
b.append(i)
print b
#[1,2,3,4,5,6] - The same order as the set in this case, since thats the order they appear in the list
import itertools
from collections import defaultdict
def list_by_count(lists):
data_stream = itertools.chain.from_iterable(lists)
counts = defaultdict(int)
for item in data_stream:
counts[item] += 1
return [item for (item, count) in
sorted(counts.items(), key=lambda x: (-x[1], x[0]))]
Having the x[0] in the sort key ensures that items with the same count are in some kind of sequence as well.

python union of 2 nested lists with index

I want to get the union of 2 nested lists plus an index to the common values.
I have two lists like A = [[1,2,3],[4,5,6],[7,8,9]] and B = [[1,2,3,4],[3,3,5,7]] but the length of each list is about 100 000. To A belongs an index vector with len(A): I = [2,3,4]
What I want is to find all sublists in B where the first 3 elements are equal to a sublist in A. In this example I want to get B[0] returned ([1,2,3,4]) because its first three elements are equal to A[0]. In addition, I also want the index to A[0] in this example, that is I[0].
I tried different things, but nothing worked so far :(
First I tried this:
Common = []
for i in range(len(B)):
if B[i][:3] in A:
id = [I[x] for x,y in enumerate(A) if y == B[i][:3]][0]
ctdCommon.append([int(id)] + B[i])
But that takes ages, or never finishes
Then I transformed A and B into sets and took the union from both, which was very quick, but then I don't know how to get the corresponding indices
Does anyone have an idea?
Create an auxiliary dict (work is O(len(A)) -- assuming the first three items of a sublist in A uniquely identify it (otherwise you need a dict of lists):
aud = dict((tuple(a[:3]), i) for i, a in enumerate(A))
Use said dict to loop once on B (work is O(len(B))) to get B sublists and A indices:
result = [(b, aud[tuple(b[:3])]) for b in B if tuple(b[:3]) in aud]

Categories