Keep duplciate items in list of tuples if only the first index matches between the tuples - python-3.x

Input [(1,3), (3,1), (1,5), (2,3), (2,4), (44,33), (33,22), (44,22), (22,33)]
Expected Output [(1,3), (1,5), (2,3), (2,4), (44,33), (44,22)]
I am trying to figure out the above and have tried lots of stuff. So far my only success has been,
for x in range(len(list1)):
if list1[0][0] == list1[x][0]:
print(list1[x])
Output: (1, 3) \n (1, 5)
Any sort of advice or help would be appreciated.

Use a collections.defaultdict(list) keyed by the first value, and keep only the values that are ultimately duplicated:
from collections import defaultdict # At top of file, for collecting values by first element
from itertools import chain # At top of file, for flattening result
dct = defaultdict(list)
inp = [(1,3), (3,1), (1,5), (2,3), (2,4), (44,33), (33,22), (44,22), (22,33)]
# For each tuple
for tup in inp:
first, _ = tup # Extract first element (and verify it's actually a pair)
dct[first].append(tup) # Collect with other tuples sharing the same first element
# Extract all lists which have two or more elements (first element duplicated at least once)
# Would be list of lists, with each inner list sharing the same first element
onlydups = [lst for firstelem, lst in dct.items() if len(lst) > 1]
# Flattens to make single list of all results (if desired)
flattened_output = list(chain.from_iterable(onlydups))
Importantly, this doesn't required ordered input, and scales well, doing O(n) work (scaling your solution naively would produce a O(n²) solution, considerably slower for larger inputs).

Another approach is the following :
def sort(L:list):
K = []
for i in L :
if set(i) not in K :
K.append(set(i))
output = [tuple(m) for m in K]
return output
output :
[(1, 3), (1, 5), (2, 3), (2, 4), (33, 44), (33, 22), (44, 22)]

Related

How to only print next iteration of a permutation

So basically I have a list of 26 objects (the letters of the alphabet)
I would like to be able to find what the next iteration of the permutation would be.
However to compute the entire permutation list and store this as a list to iterate through will take too much computational power as the total number of possible iterations is 403291461126605635584000000
import itertools
print(list(itertools.permutations(['a','b','c','d','e','f','g','h','i','j','k','l','m','n','o','p','q','r','s','t','u','v','w','x','y','z'], 26)))
For example.
If I had a small list of say 3 letters this would be much more straight forward.
import itertools
x = list(itertools.permutations(['a','b','c'], 3))
print(x[2])
The method itertools.permutations is a generator function, which will create the next permutation when requested (calling next() on the generator object or iterating over it). All permutations will only be created in the case where you cast it to a list (which you are doing) or when you iterate over all of them.
from itertools import permutations
permutation_generator = permutations("ABCD", 2)
print(next(permutation_generator))
# Output: ('A', 'B')
print(next(permutation_generator))
# Output: ('A', 'C')
print(next(permutation_generator))
# Output: ('A', 'D')
# Example of iterating with a generator and stopping after two iterations
for i, permutation in enumerate(permutation_generator):
if i > 1:
break
print(permutation)
# Output:
# ('B', 'A')
# ('B', 'C')
# Generating the next five permutations in a list
permutations_first_five = [next(permutation_generator) for _ in range(5)]

Given a list of lists, how can i create another specific kind of list

So what I exactly want to do is make a list of lists from another list of lists, but this new list takes the positions of each of the lists in the original list and makes a new one.
for example.
[[5,6,3],[2,0,4],[3,8,5]]
would become
[[5,2,3],[6,0,8],[3,4,5]]
so the new list is the 0th position's of the old listoflists and 1st position and so on.
You can make separate lists and then combine them to new lists.
list = [[5,6,3],[2,0,4],[3,8,5]]
new_list_0 = [list[i][0] for i in range(0, len(list))]
new_list_1 = [list[i][1] for i in range(0, len(list))]
new_list_2 = [list[i][2] for i in range(0, len(list))]
new_list = []
new_list.append(new_list_0)
new_list.append(new_list_1)
new_list.append(new_list_2)
print(new_list)
But appending new lists will be cumbersome.
list(zip(*list)) gives list of tuples
list_of_numbers = [[5,6,3],[2,0,4],[3,8,5]]
new_list_of_numbers = list(zip(list_of_numbers[0], list_of_numbers[1], list_of_numbers[2]))
print(new_list_of_numbers)
Output:
[(5, 2, 3), (6, 0, 8), (3, 4, 5)]

What is the best possible way to find the first AND the last occurrences of an element in a list in Python?

The basic way I usually use is by using the list.index(element) and reversed_list.index(element), but this fails when I need to search for many elements and the length of the list is too large say 10^5 or say 10^6 or even larger than that. What is the best possible way (which uses very little time) for the same?
You can build auxiliary lookup structures:
lst = [1,2,3,1,2,3] # super long list
last = {n: i for i, n in enumerate(lst)}
first = {n: i for i, n in reversed(list(enumerate(lst)))}
last[3]
# 5
first[3]
# 2
The construction of the lookup dicts takes linear time, but then the lookup itself is constant.
Whreas calls to list.index() take linear time, and repeatedly doing so is then quadratic (given the number of lookups you make depends on the size of the list).
You could also build a single structure in one iteration:
from collections import defaultdict
lookup = defaultdict(lambda: [None, None])
for i, n in enumerate(lst):
lookup[n][1] = i
if lookup[n][0] is None:
lookup[n][0] = i
lookup[3]
# [2, 5]
lookup[2]
# [1, 4]
Well, someone needs to do the work in finding the element, and in a large list this can take time! Without more information or a code example, it'll be difficult to help you, but usually the go-to answer is to use another data structure- for example, if you can keep your elements in a dictionary instead of a list with the key being the element and the value being an array of indices, you'll be much quicker.
You can just remember first and last index for every element in the list:
In [9]: l = [random.randint(1, 10) for _ in range(100)]
In [10]: first_index = {}
In [11]: last_index = {}
In [12]: for idx, x in enumerate(l):
...: if x not in first_index:
...: first_index[x] = idx
...: last_index[x] = idx
...:
In [13]: [(x, first_index.get(x), last_index.get(x)) for x in range(1, 11)]
Out[13]:
[(1, 3, 88),
(2, 23, 90),
(3, 10, 91),
(4, 13, 98),
(5, 11, 57),
(6, 4, 99),
(7, 9, 92),
(8, 19, 95),
(9, 0, 77),
(10, 2, 87)]
In [14]: l[0]
Out[14]: 9
Your approach sounds good, I did some testing and:
import numpy as np
long_list = list(np.random.randint(0, 100_000, 100_000_000))
# This takes 10ms in my machine
long_list.index(999)
# This takes 1,100ms in my machine
long_list[::-1].index(999)
# This takes 1,300ms in my machine
list(reversed(long_list)).index(999)
# This takes 200ms in my machine
long_list.reverse()
long_list.index(999)
long_list.reverse()
But at the end of the day, a Python list does not seem like the best data structure for this.
As others have sugested, you can build a dict:
indexes = {}
for i, val in enumerate(long_list):
if val in indexes.keys():
indexes[val].append(i)
else:
indexes[val] = [i]
This is memory expensive, but solves your problem (depends on how often you modify the original list).
You can then do:
# This takes 0.02ms in my machine
ix = indexes.get(999)
ix[0], ix[-1]

3Sum using python3 and enumarate

I want to solve the following task using 'enumerate' in python3
The way enumerate works is demonstrated below
nums=(2,7,1,15) # a tuple
for num in enumerate(nums):
print(num, 'hello')
#output
#(0, 2) hello #enumarate(nums) = (0,2)
#(1, 7) hello
#(2, 1) hello
#(3, 15) hello
for count, num in enumerate(nums):
print(num, 'hello')
# Output
#2 hello here count=0 but not displayed
#7 hello here count=1 but not displayed
#1 hello here count=2 but not displayed
#15 hello here count=3 but not displayed
Using the above principle, given an array nums of n integers, are there elements a, b, c in nums such that a + b + c = target sum? Find all unique triplets in the array which gives the sum = target sum.
A solution set for target sum =10 is:
[
[0,1,2]
]
where num at 0th index+num at 1st index+num at 2nd index(7+2+1=10).
Do you have an idea for an algorithm to solve the problem?
I would probably do something like build up two dicts listing all the ways to use the array indexes make a sum with 1 number and 2 numbers to be a certain key value.
E.g., if I had been given nums = [2, 7, 1, 2, 3], I would write code to build up a table like:
one_sum = {1: [2],
2: [0, 3],
3: [4],
7: [1]}
I would use a defaultdict from collections module to efficiently write this code (initialized as one_sum = defaultdict(list) above, though a set would also be a valid data structure for the problem).
It would be straightforward to use enumerate for this part; e.g.,
for i, n in enumerate(nums):
one_sum[n].append(i)
Then I would then build up a two_sum table this time showing all pairs of indexes that make a certain sum. Continuing with the example above, I would want to generate:
two_sum = {3: [(0, 2), (2, 3)],
4: [(2, 4)],
5: [(0, 4), (3, 4)],
8: [(1, 2)],
9: [(0, 1), (1, 3)],
10: [(1, 4)]}
(Note one way to efficiently do this is to loop through the built up one_sum, but be careful not to re-use an index e.g., don't add (2,2) or (4,4) to two_sum[4] because while nums[2] + nums[2] does add up to 4, it uses an index twice (so isn't unique). Also be careful not to double add indexes that are out of order.)
Finally I would loop through the one_sum dict, looking at indices that sum to k and then look in two_sum to see if there are any pairs of indices that sum to target-k, and if so then join the pairs together (checking to sort indices and not repeat indices in a tuple) having found a solution.
For a target of 10 this would ideally build up
three_sum = [(0,1,2), (1,2,3)]
# Note both were added from combining one_sum[1] with two_sum[9]
# nothing from combining one_sum[2] with two_sum[8] as they reuse indexes
# nothing from combining one_sum[3] as two_sum[7]==[]
# nothing new from combining one_sum[7] with two_sum[3] as (0,1,2) and (1,2,3) already present.
Here's a brute force method. It's not as efficient as this algorithm can be, mind you.
def f(nums, target):
sols = []
for i1, n1 in enumerate(nums):
for i2, n2 in enumerate(nums[i1+1:]):
for i3, n3 in enumerate(nums[i2+1:]):
if (n1 + n2 + n3 == target):
sols.append([i1, i2, i3])
return sols

Python: How to find the average on each array in the list?

Lets say I have a list with three arrays as following:
[(1,2,0),(2,9,6),(2,3,6)]
Is it possible I get the average by diving each "slot" of the arrays in the list.
For example:
(1+2+2)/3, (2+0+9)/3, (0+6+6)/3
and make it become new arraylist with only 3 integers.
You can use zip to associate all of the elements in each of the interior tuples by index
tups = [(1,2,0),(2,9,6),(2,3,6)]
print([sum(x)/len(x) for x in zip(*tups)])
# [1.6666666666666667, 4.666666666666667, 4.0]
You can also do something like sum(x)//len(x) or round(sum(x)/len(x)) inside the list comprehension to get an integer.
Here are couple of ways you can do it.
data = [(1,2,0),(2,9,6),(2,3,6)]
avg_array = []
for tu in data:
avg_array.append(sum(tu)/len(tu))
print(avg_array)
using list comprehension
data = [(1,2,0),(2,9,6),(2,3,6)]
comp = [ sum(i)/len(i) for i in data]
print(comp)
Can be achieved by doing something like this.
Create an empty array. Loop through your current array and use the sum and len functions to calculate averages. Then append the average to your new array.
array = [(1,2,0),(2,9,6),(2,3,6)]
arraynew = []
for i in range(0,len(array)):
arraynew.append(sum(array[i]) / len(array[i]))
print arraynew
As you were told in the comments with sum and len it's pretty easy.
But in python I would do something like this, assuming you want to maintain decimal precision:
list = [(1, 2, 0), (2, 9, 6), (2, 3, 6)]
res = map(lambda l: round(float(sum(l)) / len(l), 2), list)
Output:
[1.0, 5.67, 3.67]
But as you said you wanted 3 ints in your question, would be like this:
res = map(lambda l: sum(l) / len(l), list)
Output:
[1, 5, 3]
Edit:
To sum the same index of each tuple, the most elegant method is the solution provided by #PatrickHaugh.
On the other hand, if you are not fond of list comprehensions and some built in functions as zip is, here's a little longer and less elegant version using a for loop:
arr = []
for i in range(0, len(list)):
arr.append(sum(l[i] for l in list) / len(list))
print(arr)
Output:
[1, 4, 4]

Resources