Compare elements inside list of lists in Python - python

I'm trying to create a new list of lists by removing the rows with a duplicated value within existing list of lists.
fir = [['a35',1],['a35',2],['3r',6],['3r',8],[5,9]]
sec = []
for row in fir:
if sec is None:
sec.append(row)
elif row[0] not in sec:
sec.append(row)
print(sec)
Expected output:
[['a35', 1], ['3r', 6], [5, 9]]
Actual output:
[['a35', 1], ['a35', 2], ['3r', 6], ['3r', 8], [5, 9]]
I want create a list of lists in which the values of row[0] are unique and not duplicated (e.g. the row with 'a35' should be included only once)
How can I achieve this?

you can simply save the unique value (the 1st data in the tuple), you're wrong because you compare the 1st tuple to all the data (comparing 'a35' to ['a35',1])
fir = [['a35',1],['a35',2],['3r',6],['3r',8],[5,9]]
sec = []
index = []
for f in fir:
if not f[0] in index:
index.append(f[0])
sec.append(f)
print(sec)

Your current code fails because after the first iteration sec looks like this: [['a35',1]]. On the second iteration row has value of ['a35',2] which can't be found from sec thus it gets appended there.
You could use groupby to group the inner lists based on the first element. groupby returns iterable of (key, it) tuple where key is value returned by second parameter and it is iterable of elements in within the group:
>>> from itertools import groupby
>>> fir = [['a35',1],['a35',2],['3r',6],['3r',8],[5,9]]
>>> [next(g) for _, g in groupby(fir, lambda x: x[0])]
[['a35', 1], ['3r', 6], [5, 9]]
Note that above assumes that lists with the same first element are next to each other in seq. If that's not the case you could sort seq before passing it to groupby but that only works if the first elements can be used as keys. With your data that's not the case since there are strings and ints which can't be compared on Python 3. You could collect the items to OrderedDict though:
from collections import OrderedDict
fir = [['a35',1],['a35',2],['3r',6],['3r',8],[5,9],['a35',7]]
d = OrderedDict()
for x in fir:
d.setdefault(*x)
print([list(x) for x in d.items()])
Output:
[['a35', 1], ['3r', 6], [5, 9]]

Use List Comprehension to achieve this:
sec=[i for i in fir if i[0] not in [fir[idx][0] for idx in xrange(0,fir.index(i))]]
This selects each item from fir and compare first element of the item with all the item from index 0 till the index of that item.
As you have only two items in the inner list and you don't want to have duplicates,
Dictionary would have been the perfect data structure for your case.

I think when you loop the fir, you should add a list for recording which key you have put in the sec.

Related

I like to eliminate duplicate component from double list and combine it

I like to combine double lists with duplicate components. It is python code.
import Tb= [[1],[1,3],[1,2],[5,7]]
expected output Tc=[[1,2,3],[5,7]]
for i in range(len(Tb)):
print(i)
for a in Tb[i]:
for j in range(len(Tb)):
if a in Tb[j]:
print('yes')
Tc.append(list(set(Tb[i]).union(set(Tb[j]))))
if len(Tb[i]) >= len(Tb[j]):
Tb.pop(j)
elif len(Tb[i])<=len(Tb[j]):
Tb.pop(i)
print(Tb)
print('#'*20)
print(Tc)
I got list index out of range error.
If you delete items from a list while you are iterating through it, the for-loop will eventually try to access items beyond the list size.
It is preferable to use a while loop for in-place deletion so that you can control the progression of the index in accordance with your item manipulations.
Tb= [[1],[1,3],[1,2],[5,7]]
i = 1
while i<len(Tb):
if set(Tb[i]).isdisjoint(Tb[i-1]):
i += 1
else:
Tb[i-1] = sorted({*Tb[i],*Tb.pop(i-1)})
print(Tb)
[[1, 2, 3], [5, 7]]
Unless your list is huge, you should consider creating a second list with the merged sublists, and not have worry about index progression at all:
Tb = [[1],[1,3],[1,2],[5,7]]
Tb2 = Tb[:1]
for t in Tb[1:]:
if set(t).isdisjoint(Tb2[-1]):
Tb2.append(t)
else:
Tb2[-1] = sorted({*t,*Tb2[-1]})
print(Tb2)
[[1, 2, 3], [5, 7]]

Basic question about replacing entries in list of lists according to if condition

How can I change this code so the I replace the elements for a different if condition?
In the code below I change replace the 3 with 5.
But what if the wanted to replace the entry to 5 if any sub-list entry is larger than 30?
Example: If L[i][j] > 30 I get [[3,3],[5,5],[5,1], [5,8]]
L = [[3,3],[444,1111],[45,1], [90,8]]
for i, x in enumerate(L):
for j, a in enumerate(x):
if 3 in a:
L[i][j] = a.replace(3, 5)
****** Disclaimer *******:
The example was taken from this enclosed question for the sake of convenience. My aim in this question is to understand how to use the indexes so it fits a different type of if condition.
Replace elements in a list of lists python
Quick and dirty answer:
L = [[3,3],[444,1111],[45,1], [90,8]]
L = [[5 if value < 30 else 5 for value in list ] for list in L]
print(L)
out:
[[3, 3], [5, 5], [5, 1], [5, 8]]
Better way using a function
If you want to replace the values then it's better to create a simple function as shown below. You seem to have copied the code from somewhere else, so I will try my best to explain to you what is going on below.
Our original list is shown below:
L = [[3,3],[444,1111],[45,1], [90,8]]
The function below is defined to accept 3 values, the first value is the list to be manipulated, the second is the condition, as in replace if number is > condition. The third value is the new value to replace the values that satisfy the condition.
def replace_greater_than(List,condition = 30,new_value = 5):
L = [[value if value < condition else new_value for value in list ] for list in List]
Here we are using a concept know as nested list comprehension. Start by reading it from right to left. We are looping through every list in List (notice the case), please note that "list" in the code can be replaced with any variable name that you want, but i just called it "list" to improve readability.
So now we are looping through our initial list and we are retrieving the inner lists with each iteration.Then we perform list comprehension again on the inner lists that we just retrieved, so now we are looping on the values in the list themselves.
Finally in the inner list comprehension we set a condition, which is passed on by the user, if the value is less than the set condition or threshold then return the same value else return the specified new value.
How to use the function:
Example: here we place the condition as 30 and the value as 5
replace_greater_than(List = L, condition = 30, value = 5)
out:
[[3, 3], [5, 5], [5, 1], [5, 8]]
Example: We can also call the function without passing any values to the parameters because we already set the default values of our function earlier; condition = 30, new_value = 5.
replace_greater_than(List = L)
out:
[[3, 3], [5, 5], [5, 1], [5, 8]]
Example: Finally, we can also pass custom values to our function. The function below will replace all the values greater than 100 with the new_value of 23
replace_greater_than(List = L, condition = 100, new_value = 23)
out:
[[3, 3], [23, 23], [45, 1], [90, 8]]
Here are some sources to help you get started with learning python:
Great free Course covering all the basics by Microsoft
List Comprehension
Functions in python
Some channels on Youtube that I recommend:
Real Python
Corey Schafer
DataCamp
Basically you have a loop through all elements, then you have condition and action when condition is met.
for i, x in enumerate(L): #loop
for j, a in enumerate(x): #loop
if 3 in a: #condition
L[i][j] = a.replace(3, 5) #action
You want to change condition to if L[i][j] > 30 (already in your question), and you want to change action to replace or reassign entry, which is straightforward L[i][j] = 5.
In above code a is L[i][j], so you can write condition a bit differently.
I will let you modify code yourself and test. You don't need to use list comprehension at this point.
Thea easy way to do it is to iterate over each item in each list and change items via an 'if' statement.
Create a statement which will return either the item it is given, or 3 if the number is equal to 5.
replace = lambda i: 3 if i==5 else i
Next, iterate through the nested lists. This can be written out in two ways, via list comprehension or as nested for statements.
l = [[replace(l2)for l2 in l1] for l1 in l]
for l1 in l:
for l2 in l1:
l2 = replace(l2)
When we run the code we get:
print (l)
>>> [[3, 3], [444, 1111], [45, 1], [90, 8]]
To make the code change any items <30 we can change the if statement we made at the start.
replace = lambda i: 3 if i<30 else i
Printing the new code gives:
print (l)
>>> [[3, 3], [444, 1111], [45, 3], [90, 3]]
Note, using x.replace() works for strings not integers, you can play with int() and str() if you need to use .replace().

Get one resulting list with the max or min by index in a nested list

Lets say I have this structure
[[[1,2],[3,4]],[[8,9],[7,7]]]
I want to iterate the list and have this result:
[[3,2],[8,7]]
This is would be reducing the list list of arrays in the first level [[1,2],[3,4]] to one single array where the maximum selected for the first element and the minimum is found for the second.
I have already done it manually, just iterating the groups, iterating again, storing the first value and seeing if the next is bigger or smaller, I store it in a list and create another list.
I would like to find a more elegant method with list comprehensions and so on, I'm pretty sure I can use zip here to group the values in the same group but I haven't been successful so far.
You can use zip, and by unpacking the result into individual values it is pretty easy to do what you are looking for, e.g.:
>>> x = [[[1,2],[3,4]],[[8,9],[7,7]]]
>>> [[max(a), min(b)] for k in x for a, b in [zip(*k)]]
[[3, 2], [8, 7]]
An alternative way without unpacking is to have a cycling function iterable (max, min, max, min, ...) and use nested list comprehensions, e.g.:
>>> import itertools as it
>>> maxmin = it.cycle([max, min])
>>> [[next(maxmin)(a) for a in zip(*k)] for k in x]
[[3, 2], [8, 7]]
Or index into a list of functions:
>>> import itertools as it
>>> maxmin = [max, min]
>>> [[maxmin[i](a) for i, a in enumerate(zip(*k))] for k in x]
[[3, 2], [8, 7]]
This will work without zip:
mylist = [[[1,2],[3,4]],[[8,9],[7,7]]]
[[max(y[0] for y in x), min(y[1] for y in x)] for x in mylist]
The main disadvantage of this is that it looks through each sub-list twice, once to find the maximum (of the first items) and once to find the minimum (of the second items).

Groupby for nestedlists

I have a list [[1,20],[1,30],[2,30],[2,50],[3,60], [1,20]]. If the first elements on the nested list is same as previous, i should remove that(not removing the duplicates on the list). In this case, i should get as [[1,20],[2,30],[3,60],[1,20]].
I am using itemgetter and groupby and have written this:
[x[0] for x in groupby(testlist, itemgetter(0))]
The above code outputs only the first element as [1, 2, 3, 1]. I want this to be in the same nested list format as [[1,20],[2,30],[3,60],[1,20]]. How can i do this in-place on the same list, 'testlist'. Is there any better way to achieve this than simply iterating the whole list again.
You're only showing the keys. itertools.groupby returns a tuple of keys and groups. You need the first item in the groups:
print [next(g) for k, g in groupby(i, itemgetter(0))]
# # [[1, 20], [2, 30], [3, 60], [1, 20]]

How to pick the smallest value in a list when an iterative process is applied to the list

I need to find the smallest value in a series of lists. I understand the code for the smallest value in just one list:
>>> x = [1, 2, 3, 4, 5]
>>> print (min(x))
1
Simple enough. However, I would like to know if there is a way to write code that finds the smallest value for each list I have without stopping and adjusting the code (whether by an iterative process or some other means). Any help would be greatly appreciated. Thanks in advance!
First, make a list of lists out of your separate lists. For example, if you have lists A, B and C, the list of lists would be [A,B,C].
Now, to get a list of all the minimum values for each list in a list of lists lst:
[min(x) for x in lst]
To get the global minimum:
min(x for sublist in lst for x in sublist)
Demo:
>>> lst
[[1, 2, 3], [4, 5, 6], [7, 8, 9]]
>>> [min(x) for x in lst]
[1, 4, 7]
>>> min(x for sublist in lst for x in sublist)
1
Edit in reaction to OP's comment:
I just want the minimum value for each list. I don't need to compile all of the minimum values together into a new list
If you just want to print the minimum values for each list A, B, C, ... , you can do:
for lst in (A,B,C): # put as many lists as you like into the parentheses
print(min(lst))
Edit in reaction to
I am only accessing one list (in this case, the values are well depths) at a time. [..] What I would like to know is how to write a code that finds the smallest value in a list given that the iterator essentially changes the values in said list.
Just print(min(lst)) each time lst has changed.
Assuming you've got a list of lists, this should do it:
minimums = [min(l) for l in lists]

Categories