Associating values from one list with values in another programmatically - python

(Asking again in a more concise way)
I have four lists of values and I need to link the first and last together like this:
so that I can plot the points (4, 8350.1416), (10, 13167.329), (15, 29200.063), etc.
The enumerate function can give me access to the indices of the rightmost list, but how can I associate the values in that one with the correct values in the leftmost list?
The lists change with each run of the code, so I need to do it programmatically, like in a for loop for example.
EDIT: My program reads the pixel values along a randomly selected row. List1 holds the minimum-valued pixels, and list2 holds their values. Then list3 holds the minimum values of those minimum values, and list4 holds their values. Describing it like that sounds a lot more confusing than it is!
I've tried using
ubermin_vals_x = []
for i in ubermin_values:
value = ubermin_pixels[i]
ubermin_vals_x.append(minimum_pixels[i])
but it tries to iterate over the values (8350.1416, 13167.329...) which of course can't be done.
I'm trying to plot the lists to look like this:
but have the black carets from list4 at the correct points along the x-axis, which are given in list1.

Naming lists from left to right as l1,l2,l3,l4 l2 seems useless to me, since it just replicates the value in l4, so if I understand the problem, the code could be:
for i,v in zip(l3,l4):
print (l1[i],v) #or plot
and you can replace v with l2[i].
Or even simpler:
for i in l3:
print (l1[i],l2[i])
As from comment below in your example elements of l3 seem to be sigle-element list, the code becomes:
for i in l3:
print (l1[i[0]],l2[i[0]])

It's not very clear to me what you are trying to do, but here is my guess
find the index of element in 4th array in 2nd array
use that index to extract the number in 1st array
and the implementation is as follows
a4 = [ 8350.1416, 13167.329, 29200.063 ]
a2 = [13846, 8350.1416, 0, 13167.329, 0, 29200.063]
a1 = [1, 4, 7, 10, 12, 15, 18]
idx = [a1[a2.index(x)] for x in a4]
result = zip(idx, a4)
I also suspect #Vincenzooo 's answer is already very close to what you want. Maybe
for i in l3:
print (l1[i[0]],l2[i[0]])

Thanks, everyone, especially #Vincenzoo
It works now with this:
uberminxlist = []
uberminylist = []
for i in ubermin_pixels:
uberminxlist.append(minimum_pixels[i[0]])
uberminylist.append(minimum_values[i[0]])
Lovely :)

Related

Find minimum values of both "columns" of list of lists

Given a list like the next one:
foo_list = [[1,8],[2,7],[3,6]]
I've found in questions like Tuple pairs, finding minimum using python and
minimum of list of lists that the pair with the minimum value of a list of lists can be found using a generator like:
min(x for x in foo_list)
which returns
[1, 8]
But I was wondering if there is a similar way to return both minimum values of the "columns" of the list:
output = [1,6]
I know this can be achieved using numpy arrays:
output = np.min(np.array(foo_list), axis=0)
But I'm interested in finding such a way of doing so with generators (if possible).
Thanks in advance!
[min(l) for l in zip(*foo_list)]
returns [1, 6]
zip(*foo_list) gets the list transpose and then we find the minimum in both lists.
Thanks #mousetail for suggestion.
You can use two min() for this. Like -
min1 = min(a for a, _ in foo_list)
min2 = min(b for _, b in foo_list)
print([min1, min2])
Will this do? But I think if you don't want to use third party library, you can just use plain old loop which will be more efficient.

Grouping lists of numbers together in Python

I have the following which is a list of a list in Python, and is a partial list of values that I have:
[1,33]
[2,10,42]
[5,1,33,44]
[10,42,98]
[44,12,100,124]
Is there a way of grouping them so they collect the values that are common in each list?
For example, if I look at the first list [1,33], I can see that the value exists in the third list: [5,1,33,44]
So, those are grouped together as
[5,1,33,44]
If I carry on looking, I can see that 44 is in the final list, and so that will be grouped along with this list.
[44,12,100,124] is added onto [5,1,33,44]
to give:
[1,5,12,33,44,100,124]
The second list [2,10,42] has common values with [10,42,98] and are therefore joined together to give:
[2,10,42,98]
So the final lists are:
[1,5,12,33,44,100,124]
[2,10,42,98]
I am guessing there is a specific name for this type of grouping. Is there a library available that can deal with it automatically? Or would I have to write a manual way of searching?
I hope the edit makes it clearer as to what I am trying to achieve.
Thanks.
Here's a solution that does not require anything from the standard library or 3rd party packages. Note that this will modify a. To avoid that, just make a copy of a and work with that. The result is a list of lists containing your resulting sorted lists.
a = [
[1,33],
[2,10,42],
[5,1,33,44],
[10,42,98],
[44,12,100,124]
]
res = []
while a:
el = a.pop(0)
res.append(el)
for sublist in a:
if set(el).intersection(set(sublist)):
res[-1].extend(sublist)
a.remove(sublist)
res = [sorted(set(i)) for i in res]
print(res)
# [[1, 5, 12, 33, 44, 100, 124], [2, 10, 42, 98]]
How this works:
Form an empty result list res. Groupings from a will be "transferred" here.
.pop() off the first element of a. This modifies a in place and defines el as that element.
Then loop through each sublist in a, comparing your popped el to those sublists and "building up" common sets. This is where your problem is a tiny bit tricky in that you need to gradually increment your intersected set rather than finding the intersection of multiple sublists all at once.
Repeat this process until a is empty.
Alternatively, if you just want to group together the even- and odd-numbered sublists (still a bit unclear from your question), you can use itertools:
from itertools import chain
grp1 = sorted(set(chain.from_iterable(a[::2])))
grp2 = sorted(set(chain.from_iterable(a[1::2])))
print(grp1)
print(grp2)
# [1, 5, 12, 33, 44, 100, 124]
# [2, 10, 42, 98]

Randomly remove 'x' elements from a list

I'd like to randomly remove a fraction of elements from a list without changing the order of the list.
Say I had some data and I wanted to remove 1/4 of them:
data = [1,2,3,4,5,6,7,8,9,10]
n = len(data) / 4
I'm thinking I need a loop to run through the data and delete a random element 'n' times? So something like:
for i in xrange(n):
random = np.randint(1,len(data))
del data[random]
My question is, is this the most 'pythonic' way of doing this? My list will be ~5000 elements long and I want to do this multiple times with different values of 'n'.
Thanks!
Sequential deleting is a bad idea since deletion in a list is O(n). Instead do something like this:
def delete_rand_items(items,n):
to_delete = set(random.sample(range(len(items)),n))
return [x for i,x in enumerate(items) if not i in to_delete]
You can use random.sample like this:
import random
a = [1,2,3,4,5,6,7,8,9,10]
no_elements_to_delete = len(a) // 4
no_elements_to_keep = len(a) - no_elements_to_delete
b = set(random.sample(a, no_elements_to_keep)) # the `if i in b` on the next line would benefit from b being a set for large lists
b = [i for i in a if i in b] # you need this to restore the order
print(len(a)) # 10
print(b) # [1, 2, 3, 4, 5, 8, 9, 10]
print(len(b)) # 8
Two notes on the above.
You are not modifying the original list in place but you could.
You are not actually deleting elements but rather keeping elements but it is the same thing (you just have to adjust the ratios)
The drawback is the list-comprehension that restores the order of the elements
As #koalo says in the comments the above will not work properly if the elements in the original list are not unique. I could easily fix that but then my answer would be identical to the one posted by#JohnColeman. So if that might be the case just use his instead.
Is the order meaningful?
if not you can do something like:
shuffle(data)
data=data[:len(data)-n]
I suggest using numpy indexing as in
import numpy as np
data = np.array([1,2,3,4,5,6,7,8,9,10])
n = len(data)/4
indices = sorted(np.random.choice(len(data),len(data)-n,replace=False))
result = data[indices]
I think it will be more convenient this way:
import random
n = round(len(data) *0.3)
for i in range(n):
data.pop(random.randrange(len(data)))

Basic python: how to increase value of item in list [duplicate]

This question already has answers here:
Why does this iterative list-growing code give IndexError: list assignment index out of range? How can I repeatedly add (append) elements to a list?
(9 answers)
Closed 4 months ago.
This is such a simple issue that I don't know what I'm doing wrong. Basically I want to iterate through the items in an empty list and increase each one according to some criteria. This is an example of what I'm trying to do:
list1 = []
for i in range(5):
list1[i] = list1[i] + 2*i
This fails with an list index out of range error and I'm stuck. The expected result (what I'm aiming at) would be a list with values:
[0, 2, 4, 6, 8]
Just to be more clear: I'm not after producing that particular list. The question is about how can I modify items of an empty list in a recursive way. As gnibbler showed below, initializing the list was the answer. Cheers.
Ruby (for example) lets you assign items beyond the end of the list. Python doesn't - you would have to initialise list1 like this
list1 = [0] * 5
So when doing this you are actually using i so you can just do your math to i and just set it to do that. there is no need to try and do the math to what is going to be in the list when you already have i. So just do list comprehension:
list1 = [2*i for i in range(5)]
Since you say that it is more complex, just don't use list comprehension, edit your for loop as such:
for i in range(5):
x = 2*i
list1[i] = x
This way you can keep doing things until you finally have the outcome you want, store it in a variable, and set it accordingly! You could also do list1.append(x), which I actually prefer because it will work with any list even if it's not in order like a list made with range
Edit: Since you want to be able to manipulate the array like you do, I would suggest using numpy! There is this great thing called vectorize so you can actually apply a function to a 1D array:
import numpy as np
list1 = range(5)
def my_func(x):
y = x * 2
vfunc = np.vectorize(my_func)
vfunc(list1)
>>> array([0, 2, 4, 6, 8])
I would advise only using this for more complex functions, because you can use numpy broadcasting for easy things like multiplying by two.
Your list is empty, so when you try to read an element of the list (right hand side of this line)
list1[i] = list1[i] + 2*i
it doesn't exist, so you get the error message.
You may also wish to consider using numpy. The multiplication operation is overloaded to be performed on each element of the array. Depending on the size of your list and the operations you plan to perform on it, using numpy very well may be the most efficient approach.
Example:
>>> import numpy
>>> 2 * numpy.arange(5)
array([0, 2, 4, 6, 8])
I would instead write
for i in range(5):
list1.append(2*i)
Yet another way to do this is to use the append method on your list. The reason you're getting an out of range error is because you're saying:
list1 = []
list1.__getitem__(0)
and then manipulate this item, BUT that item does not exist since your made an empty list.
Proof of concept:
list1 = []
list1[1]
IndexError: list index out of range
We can, however, append new stuff to this list like so:
list1 = []
for i in range(5):
list1.append(i * 2)

python multimdimensional sorting, combined values

I have a multidimensional list where I would like to sort on a combined weighting of two numeric elements, example, of results using: sorted(results, key=operator.itemgetter(2,3))
[..,1,34]
...
...
[..,10,2]
[..,11,1]
[..,13,3]
[..,13,3]
[..,13,3]
[..,16,1]
[..,29,1]
The problem with itemgetter is that is first sorts by element 2, then by element 3, where
I would like to have the 13,3 at the top/bottom (dependent on asc/desc sort).
Is this possible and if so how.
Many thanks
Edit 1.
Sorry for being obtuse, I am processing dom data, results from search pages, it's a generic search engine searcher, so to speak.
What I am doing is finding the a and div tags, then I create a count how many items a particular class or id occurs the the div/a tag, this is element 2, then I rescan the list of found tags again and see what other class/id's for the tags match the total for the current tag being processed, thus in this case item 13,3 has 13 matches for class/id for that type of tag, and 3 denotes that there are 3 other tags with class/id's that occur the same amount of times, hence why I wish to sort like that, and no, it is not a dict, it's definitely a list.
Thank you.
I'm making a total guess here, given lack of any other explanation, and assuming what you're actually trying to do is sort by the product of the last two keys in your list, secondarily sorted by magnitude of the first element in the product. That's the only explanation I can come up with offhand for why (13,3) would be the top result.
In that case, you'd be looking for something like this:
sorted(results, key=lambda x: (x[-2]*x[-1], x[-2]), reverse=True)
That would give you the following sort:
[[13, 3], [13, 3], [13, 3], [1, 34], [29, 1], [10, 2], [16, 1], [11, 1]]
Alternatively, if what you're actually looking for here is to have the results ordered by the number of times they appear in your list, we can use a collections.Counter. Unfortunately, lists aren't hashable, so we'll cheat a bit and convert them to tuples to use as the keys. There are ways around this, but this is the simplest way for me for now to demonstrate what I'm talking about.
import collections, json
def sort_results(results):
c = collections.Counter([tuple(k) for k in results])
return sorted(c, key=lambda x: c[x], reverse=True)
This gets you:
[(13, 3), (1, 34), (16, 1), (29, 1), (11, 1), (10, 2)]
Thanks J.F. Sebastian for pointing out that tuples could be used instead of str!
Yes, you can write whatever function you want as the key function. For example, if you wanted to sort by the sum of the second and third elements:
def keyfunc(item):
return sum(operator.itemgetter(2, 3)(item))
sorted(results, key=keyfunc)
So if you used this function as your keyfunc, the item with 13 as the second element 3 as the third element of the list would be sorted as though it were the value 16.
It's not clear how you want to sort these elements, but you can change the body of keyfunc to perform whatever operation you'd like.

Categories

Resources