Compare Dictionary Values that belongs to different keys - python

I have a dictionaries inside a list like this:
sample_dict = [{1: [[1, 2, 3, 4, 5, 6, 7, 8, 9, 10], \
[1, 2, 3, 4, 5], \
[1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11]]}, \
{2: [[3, 4, 6, 7, 8, 9, 10, 11], [1, 2, 3, 6, 10], []]}]
Now, I would like to check the key 1's first value in the list with key 2's first value.
something like this,
Compare Values (first value of list of lists of key 1)
[1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
with (first value of list of lists of key 2)
[3, 4, 6, 7, 8, 9, 10, 11]
If they are a match I would like to append it to a new list matching_list, if not I would to append non-matching values into another list non_matching_list.
This is what I tried so far,
matching_list = []
non_matching_list = []
for each_dict in sample_dict:
current_dict_values = []
for key, value_list in each_dict.items():
temp_dict_values = []
for value in value_list:
temp_dict_values.append(value)
.... don't know how to keep track of key 1's first list of lists values.
I was thinking of creating a temporary list to keep track of key 1 list values, but I am stuck and not sure how to proceed.
My final output should be like this:
matching_list = [[3,4,6,7,8,9,10], [1,2,3], []]
non_matching_list = [[1,2,5,11],[4,5,6,10],[1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11]]
How can I achieve my output? Any ideas would be great.

This can be achieved by converting lists to sets to make operations like symmetric_difference() and intersection() for your non_matching_list and matching_list respectively.
Here is one of the solutions:
matching_list, non_matching_list = [], []
for lists1, lists2 in zip(sample_dict[0].values(), sample_dict[1].values()):
for l1, l2 in zip(lists1, lists2):
matching_list.append(list(set(l1) & set(l2)))
non_matching_list.append(list(set(l1).symmetric_difference(set(l2))))
Note that using set(l1) & set(l2) is same as set(l1).intersection(set(l2)), so basically it's an intersection operation here.
I'm also using builtin zip() function to aggregate elements from each of the iterables ( both lists ).

Related

Removing Duplicate Numbers in a list with a twist

I have looked around and found the
if numbers.count(x) >= 2:
numbers.remove(x)
print(numbers)
but I don't want to use that. I think lazy-ier way is to go like this:
numbers = [1, 2, 3, 4, 5, 5, 6, 7, 8, 9, 2, 5, 12]
numbers.sort()
print(numbers)
duplicate = 0
for each_item in numbers:
if duplicate == each_item:
numbers.remove(each_item)
else:
duplicate += 1
print(numbers)
I, first, sort the list then print it for manual comparison. I add a variable called duplicate and set it to 0. I go thru the loop for each number in the list numbers. If I find the duplicate's value same as a number in the list, I remove it and go thru the loop, else I increase the value by 1 and print the list.
The problem is if there are more than 2 duplicates in the list it doesn't work. Which I don't understand why. I run the code in my head and it should work "flawlessly"?
Thank you for your time sensei's
Current output is;
[1, 2, 2, 3, 4, 5, 5, 5, 6, 7, 8, 9, 12]
[1, 2, 3, 4, 5, 5, 6, 7, 8, 9, 12]
Use a set to make things easy:
numbers = [1, 2, 3, 4, 5, 5, 6, 7, 8, 9, 2, 5, 12]
s = set(numbers)
print(list(s))
[1, 2, 3, 4, 5, 6, 7, 8, 9, 12]
You are changing an iterable as you iterate over it. That causes unpredictable behavior, like "skipping" an item in that list. There's plenty of resources on the internet describing the details (for instance).
Instead, iterate over a copy:
for each_item in numbers[:]:
(...)

How to make ascending sublists in a list of integers go in descending order?

Working on some example questions, the particular one asks to make a function which would take a list and return a new one which would make every ascending sublist in the list go in descending order and leave the descending sublists as they are. For example, given the list [1,2,3,4,5], I need the list [5,4,3,2,1] or given a list like [1,2,3,5,4,6,7,9,8] would return [5,3,2,1,9,7,6,4,8]
Here's what I have so far, but it does not do anything close to what I'd like it to do:
def example3(items):
sublst = list()
for i in items:
current_element = [i]
next_element = [i+1]
if next_element > current_element:
sublst = items.reverse()
else:
return items
return sublst
print (example3([1,2,3,2])) #[[1, 2, 3, 2], [1, 2, 3, 2], [1, 2, 3, 2], [1, 2, 3, 2]]
EDIT:
I feel like people are a little confused as to what I want to do in this case, heres a better example of what I'd like my function to do. Given a list like: [5, 7, 10, 4, 2, 7, 8, 1, 3] I would like it to return [10, 7, 5, 4, 8, 7, 2, 3, 1]. As you can see all the sublists that are in descending order such as ([5,7,10]) gets reversed to [10, 7, 5].
It was a bit challenging to figure out what you need.
I think you want something like as follows:
import random
l = [5, 7, 10, 4, 2, 7, 8, 1, 3]
bl =[]
while True:
if len(l) == 0:
break
r = random.randint(0, len(l))
bl.extend(l[r:None:-1])
l = l[r+1:]
print(bl)
Out1:
[10, 7, 5, 4, 8, 7, 2, 3, 1]
Out2:
[10, 7, 5, 2, 4, 1, 8, 7, 3]
Out3:
[3, 1, 8, 7, 2, 4, 10, 7, 5]
Out4:
[2, 4, 10, 7, 5, 3, 1, 8, 7]
etc.
If you want a specific reverse random list:
import random
loop_number = 0
while True:
l = [5, 7, 10, 4, 2, 7, 8, 1, 3]
bl =[]
while True:
if len(l) == 0:
break
r = random.randint(0, len(l))
bl.extend(l[r:None:-1])
l = l[r+1:]
loop_number += 1
if bl == [10, 7, 5, 4, 8, 7, 2, 3, 1]:
print(bl)
print("I tried {} times".format(loop_number))
break
Out:
[10, 7, 5, 4, 8, 7, 2, 3, 1]
I tried 336 times
The general algorithm is to keep track of the current ascending sublist you are processing using 2 pointers, perhaps a "start" and "curr" pointer. curr iterates over each element of the list. As long as the current element is greater than the previous element, you have an ascending sublist, and you move curr to the next number. If the curr number is less than the previous number, you know your ascending sublist has ended, so you collect all numbers from start to curr - 1 (because array[curr] is less than array[curr - 1] so it can't be part of the ascending sublist) and reverse them. You then set start = curr before incrementing curr.
You will have to deal with the details of the most efficient way of reversing them, as well as the edge cases with the pointers like what should the initial value of start be, as well as how to deal with the case that the current ascending sublist extends past the end of the array. But the above paragraph should be sufficient in getting you to think in the right direction.

How to add elements of python lists in a dictionary

Below is list of arrays:
{'array_1': [1, 2, 3, 4], 'array_2': [3, 4, 5, 6], 'array_3': [7, 8, 9, 0]}
Code for array input:
def main():
a = int(input("Enter the number of array's: "))
size = int(input('Each array size: '))
arrays = dict()
for i in range(1, a + 1):
arrays['array_' + str(i)] = list(
map(lambda j: int(input('value: ')), [j for j in range(size)]))
print(arrays)
I want to add 'array_1' with array_2
Just for clarification, you have a dictionary of lists, not a list of arrays. I think this is what you're looking for
list_dict = {'array_1': [1, 2, 3, 4], 'array_2': [3, 4, 5, 6], 'array_3': [7, 8, 9, 0]}
[sum(items) for items in zip(list_dict['array_1'], list_dict['array_2'])]
this results in the list [4, 6, 8, 10] - I'm assuming that's what you mean by add array_1 and array_2
If by add you mean concatenate do this:
new_list = array['array_1'] + array['array_2']
else if you mean addition of individual values you can do:
from operator import add
new_array = list(map(add,array['array_1'],array['array_2']))
If you want to sum element wise then
d= {'array_1': [1, 2, 3, 4], 'array_2': [3, 4, 5, 6], 'array_3': [7, 8, 9, 0]}
[sum(x) for x in zip(*d.values())] # will add elements from all the lists
Output:
[11, 14, 17, 10]
going along the same lines if you just want to add lists corresponding to some keys then you can filter the keys to create a new dict and use it in a same way
[sum(x) for x in zip(*{key:value for key,value in d.items() if key in ['array_1','array_2']}.values())]
Output
[4, 6, 8, 10]

Smallest number in a particular part of my list

I have a question about python. I have to sort a list of random numbers in a particular way (it's not allowed to use sort()). I'll try to explain:
I have to search for the smallest number, and swap this number with the number at the first position in the list.
Then, I search again for the smallest number, but this time ignore the first number in my list because this one is already sorted. So, I should start searching for the smallest number from the second number (index 1) till the end of the list. The smallest number then found, should be swapped with the second number in the list(so the index 1).
I hope you understand my problem. This is the code I wrote so far, but I get errors and/or the sorting isn't correct.
array = random_integers(10,size=10)
my_list = list(array)
for i in range(len(my_list)):
print my_list
a = min(my_list[i:len(my_list)])
b = my_list.index(a)
my_list[i],my_list[b]=my_list[b],my_list[i]
print my_list
I think there's a problem in my range, and a problem with the
a = min(my_list[i:len(my_list)])
I want to search for the smallest number, but not in the ENTIRE list how can I do this?
The problem occurs on this line:
b = my_list.index(a)
since this searches for the first occurrence of a in all of my_list. If the same number occurs twice, then b will always correspond to the smallest such index, which might be less than i. So you might end up moving a number which has already been sorted.
The obvious thing to try is to slice my_list before calling index:
my_list[i:].index(a)
but note that index will return values between 0 and N-i. We want numbers between i and N. So be sure to add i to the result:
b = my_list[i:].index(a)+i
Thus, the easiest way to fix your code as it presently exists is:
for i in range(len(my_list)):
a = min(my_list[i:])
b = my_list[i:].index(a)+i
my_list[i], my_list[b] = my_list[b], my_list[i]
but notice that min is searching through all the items in my_list[i:] and then the call to index is traversing the same list a second time. You could find b in one traversal like this:
b = min(range(i, N), key=my_list.__getitem__)
Demo:
import numpy as np
array = np.random.random_integers(10,size=10)
my_list = list(array)
N = len(my_list)
for i in range(N):
b = min(range(i, N), key=my_list.__getitem__)
my_list[i], my_list[b] = my_list[b], my_list[i]
print my_list
yields
[3, 10, 9, 6, 5, 3, 6, 8, 8, 4]
[3, 3, 9, 6, 5, 10, 6, 8, 8, 4]
[3, 3, 4, 6, 5, 10, 6, 8, 8, 9]
[3, 3, 4, 5, 6, 10, 6, 8, 8, 9]
[3, 3, 4, 5, 6, 10, 6, 8, 8, 9]
[3, 3, 4, 5, 6, 6, 10, 8, 8, 9]
[3, 3, 4, 5, 6, 6, 8, 10, 8, 9]
[3, 3, 4, 5, 6, 6, 8, 8, 10, 9]
[3, 3, 4, 5, 6, 6, 8, 8, 9, 10]
[3, 3, 4, 5, 6, 6, 8, 8, 9, 10]
If you want the smallest number from a list you can use min(). If you want a part of a list you can use list slicing: my_list[1:]. Put the two together and you get the smallest number from a part of your list. However, you don't need to do this, as you can .pop() from the list instead.
sorted_list = []
while my_list:
n = min(my_list)
sorted_list.append(my_list.pop(my_list.index(n)))
If you're using numpy arrays then instead of my_list.index(min(my_list)) you can use the .argmin() method.
While this type of sorting is good for an introduction, it is not very efficient. You may want to consider looking at the merge sort, and also the Python's built-in timsort.

how to create a list of lists

My Python code generates a list everytime it loops:
list = np.genfromtxt('temp.txt', usecols=3, dtype=[('floatname','float')], skip_header=1)
But I want to save each one - I need a list of lists right?
So I tried:
list[i] = np.genfromtxt('temp.txt', usecols=3, dtype=[('floatname','float')], skip_header=1)
But Python now tells me that "list" is not defined. I'm not sure how I go about defining it. Also, is a list of lists the same as an array??
Thank you!
You want to create an empty list, then append the created list to it. This will give you the list of lists. Example:
>>> l = []
>>> l.append([1,2,3])
>>> l.append([4,5,6])
>>> l
[[1, 2, 3], [4, 5, 6]]
Create your list before your loop, else it will be created at each loop.
>>> list1 = []
>>> for i in range(10) :
... list1.append( range(i,10) )
...
>>> list1
[[0, 1, 2, 3, 4, 5, 6, 7, 8, 9], [1, 2, 3, 4, 5, 6, 7, 8, 9], [2, 3, 4, 5, 6, 7, 8, 9], [3, 4, 5, 6, 7, 8, 9], [4, 5, 6, 7, 8, 9], [5, 6, 7, 8, 9], [6, 7, 8, 9], [7, 8, 9], [8, 9], [9]]
Use append method, eg:
lst = []
line = np.genfromtxt('temp.txt', usecols=3, dtype=[('floatname','float')], skip_header=1)
lst.append(line)
First of all do not use list as a variable name- that is a builtin function.
I'm not super clear of what you're asking (a little more context would help), but maybe this is helpful-
my_list = []
my_list.append(np.genfromtxt('temp.txt', usecols=3, dtype=[('floatname','float')], skip_header=1))
my_list.append(np.genfromtxt('temp2.txt', usecols=3, dtype=[('floatname','float')], skip_header=1))
That will create a list (a type of mutable array in python) called my_list with the output of the np.getfromtext() method in the first 2 indexes.
The first can be referenced with my_list[0] and the second with my_list[1]
Just came across the same issue today...
In order to create a list of lists you will have firstly to store your data, array, or other type of variable into a list. Then, create a new empty list and append to it the lists that you just created. At the end you should end up with a list of lists:
list_1=data_1.tolist()
list_2=data_2.tolist()
listoflists = []
listoflists.append(list_1)
listoflists.append(list_2)

Categories

Resources