I realise that there's a fair chance this has been asked somewhere else, but to be honest I'm not sure exactly what terminology I should be using to search for it.
But basically I've got a list with a varying number of elements. Each element contains 3 values: A string, another list, and an integer eg:
First element = ('A', [], 0)
so
ListofElements[0] = [('A', [], 0)]
And what I am trying to do is make a new list that consists of all of the integers(3rd thing in the elements) that are given in ListofElements.
I can do this already by stepping through each element of ListofElements and then appending the integer onto the new list shown here:
NewList=[]
for element in ListofElements:
NewList.append(element[2])
But using a for loop seems like the most basic way of doing it, is there a way that uses less code? Maybe a list comprehension or something such as that. It seems like something that should be able to be done on a single line.
That is just a step in my ultimate goal, which is to find out the index of the element in ListofElements that has the minimum integer value. So my process so far is to make a new list, and then find the integer index of that new list using:
index=NewList.index(min(NewList))
Is there a way that I can just avoid making the new list entirely and generate the index straight away from the original ListofElements? I got stuck with what I would need to fill in to here, or how I would iterate through :
min(ListofElements[?][2])
You can use a list coprehension:
[x[2] for x in ListOfElements]
This is generally considered a "Pythonic" approach.
You can also find the minimum in a rather stylish manner using:
minimum = min(ListOfElements, key=lambda x: x[2])
index = ListOfElements.index(minimum)
Some general notes:
In python using underscores is the standard rather than CamelCase.
In python you almost never have to use an explicit for loop. Instead prefer
coprehensions or a functional pattern (map, apply etc.)
You can map your list with itemgetter:
>>> from operator import itemgetter
>>> l = [(1, 2, 3), (1, 2, 3), (1, 2, 3), (1, 2, 3), (1, 2, 3)]
>>> map(itemgetter(2), l)
[3, 3, 3, 3, 3]
Then you can go with your approach to find the position of minimum value.
Related
Recently, I've found a code for developing a set of lists from a list, that code was written by user Mai, answering question but i have not understood it yet. Could somebody help me to understand it? And... is there a way to rewrite that code that be easier? The code is:
def even_divide(lst, num_piece=4):
return [
[lst[i] for i in range(len(lst)) if (i % num_piece) == r]
for r in range(num_piece)
]
Thanks!
It's pretty simple actually. Just follow through the values of the two loops:
Starting with the outer loop, r would be 0, then 1, then 2, etc. Let's look at the case for which r == 1. When running through the different values of i, (which would be 0, 1, 2, ... len(lst), the value of i % 4, meaning the remainder of dividing i by 4, would be 0, 1, 2, 3, 0, 1, 2, 3, .... So the i % 4 would be equal to r, for every 4 values of i!
For our chosen r == 1, that would mean we're choosing lst[1], lst[5], lst[9], ..., etc.
And for r == 2? You guessed it! You'd be picking up lst[2], lst[6], lst[10],....
So over all you'd get 4 lists, with non-overlapping elements of the original list, by just "jumping" 4 elements every time, but starting at different values.
Which naturally leads to the more simple solution:
def even_divide(lst, num_piece=4):
return [lst[r::num_piece] for r in range(num_piece)]
Could somebody help me to understand it?
Sure! It's a list comprehension. A list comprehension takes a list and does something to or with every element in that list. Let's say I want to multiply every element in my list by 2:
new_list = [element*2 for element in my_list]
What makes it a list comprehension is the bracket syntax. For those new to it, that's usually the part that takes a moment to get used to. With that said, I assume that is what is giving you difficulty in understanding the code in your question, as you have a list comprehension in a list comprehension. It might be difficult to understand now, but list comprehensions are a wonderful thing in python.
But, as this post mentions, there's a lot of discussions around list comprehension, lambda's, map, reduce, and filter. Ultimately, its up to you to decide what's best for your project. I'm not a fan of anything else but list comprehensions, so I use those religiously.
Based on the question you've linked, the list comprehension takes a 1d list of length x and turns it into a 2d list of (length x, width y). It's like numpy.reshape.
And... is there a way to rewrite that code [to] be easier?
I would not recommend it. List comprehensions are considered very pythonic and you will see them everywhere. Best to use them and get used to them.
There is a list of coordinates that I want to draw lines through on the Tkinter canvas:
points = [(1,1), (2, 2), (3, 3), (2, 0)] # etc. This is could have 100 points or more
The next step would be calling the function create_line, but it can't support list:
Canvas.create_line(1, 1, 2, 2, 3, 3) #this works ok
Canvas.create_line(points) #this doesn't work
So is there an efficient way to separate the elements in a list and insert them into the function in this order? If possible, I would love to avoid using for loops.
You can flatten the list points with a list comprehension:
flattened = [a for x in points for a in x]
And turn the elements of that flattened list into arguments with the "*" syntax:
Canvas.create_line(*flattened)
I politely suggest that you overcome your hangup about for loops. It is pretty much impossible to write useful programs without them.
I need help understanding a homework assignment that has been giving me a TON of trouble. I have attempted many different methods to get the following assignment to produce the desired result:
Create a module named task_05.py
Create a function named flip_keys() that takes one argument:
a. A list named to_flip. This list is assumed to have nested, immutable sequences inside it, eg: [(1, 2, 3), 'hello']
Use a for loop to loop the list and reverse the order of the inner sequence. All operations on the outer list must operate on the
original object, taking advantage of its mutability. Inner elements
are immutable and will require replacement.
The function should return the original list with its inner elements reversed.
My professor will evaluate the result of my script by imputing the following into python shell:
>>> LIST = [(1, 2, 3), 'abc']
>>> NEW = flip_keys(LIST)
>>> LIST is NEW
True
>>> print LIST
[(3, 2, 1), 'cba']
I don't know what I'm doing wrong and my professor hasn't responded. Students also havent responded and I have reviewed the material multiple times to try to find the answer. Something isn't clicking in my brain.
He provided the following hints, which I believe I have implimented in my script:
Hint
Consider how to access or change the value of a list. You did it
already in task 2!
Hint
In order to change the value in to_flip you'll need some way to know
which index you're attempting to change. To do-this, create a variable
to act as a counter and increment it within your loop, eg:
counter = 0 for value in iterable_object:
do something counter += 1 Now consider what that counter could represent. At the end of this loop does counter ==
len(iterable_object)
Hint
For an idea on how to reverse a tuple, head back to an earlier
assignment when you reversed a string using the slice syntax.
Heres my latest script without comments (because I don't write them in until the script works):
def flip_keys(to_flip):
for loop_list in to_flip:
to_flip = [to_flip[0][::-1], to_flip[1][::-1]]
return to_flip
When I test the script using the commands pasted above, I get these results:
>>>LIST = [(1, 2, 3), 'abc']
>>>NEW = flip_keys(LIST)
>>>LIST is NEW
False
>>>print flip_keys(LIST)
[(3, 2, 1), 'cba']
>>>print LIST
[(1, 2, 3), 'abc']
The goal of the assignment is to experiement with mutability, which I think I understand. The problem I'm facing is that the LIST variable is suppose to be updated by the function, but this never happens.
The following is supposed to evaluate to True, not false. And then print the reversed list value stored in the LIST constant.
>>>LIST = [(1, 2, 3), 'abc']
>>>NEW = flip_keys(LIST)
>>>LIST is NEW False
please let me know if this is enough information. I have spent way too much time on this and at this point my assignment is 4 days late and I'm receiving no support from professor or students (I've informed my adviser).
You are returning a new list from your function. Use a full slice [:] assignment to do an in-place mutation of the original list.
You can also use the more conventional way for creating lists - list comprehension - instead of the for loop:
def flip_keys(to_flip):
to_flip[:] = [i[::-1] for i in to_flip]
return to_flip
Test
>>> LIST = [(1, 2, 3), 'abc']
>>> NEW = flip_keys(LIST)
>>> NEW
[(3, 2, 1), 'cba']
>>> NEW is LIST
True
IMO, mutating a mutable argument and returning it doesn't feel right/conventional. This could make for a good discussion in your next class.
I was reading through some older code of mine and came across this line
itertools.starmap(lambda x,y: x + (y,),
itertools.izip(itertools.repeat(some_tuple,
len(list_of_tuples)),
itertools.imap(lambda x: x[0],
list_of_tuples)))
To be clear, I have some list_of_tuples from which I want to get the first item out of each tuple (the itertools.imap), I have another tuple that I want to repeat (itertools.repeat) such that there is a copy for each tuple in list_of_tuples, and then I want to get new, longer tuples based on the items from list_of_tuples (itertools.starmap).
For example, suppose some_tuple = (1, 2, 3) and list_of_tuples = [(1, other_info), (5, other), (8, 12)]. I want something like [(1, 2, 3, 1), (1, 2, 3, 5), (1, 2, 3, 8)]. This isn't the exact IO (it uses some pretty irrelevant and complex classes) and my actual lists and tuples are very big.
Is there a point to nesting the iterators like this? It seems to me like each function from itertools would have to iterate over the iterator I gave it and store the information from it somewhere, meaning that there is no benefit to putting the other iterators inside of starmap. Am I just completely wrong? How does this work?
There is no reason to nest iterators. Using variables won't have a noticeable impact on performance/memory:
first_items = itertools.imap(lambda x: x[0], list_of_tuples)
repeated_tuple = itertools.repeat(some_tuple, len(list_of_tuples))
items = itertools.izip(repeated_tuple, first_items)
result = itertools.starmap(lambda x,y: x + (y,), items)
The iterator objects used and returned by itertools do not store all the items in memory, but simply calculate the next item when it is needed. You can read more about how they work here.
I don't believe the combobulation above is necessary in this case.
it appears to be equivalent to this generator expression:
(some_tuple + (y[0],) for y in list_of_tuples)
However occasionally itertools can have a performance advantage especially in cpython
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.