I am relatively new to programming, and have this problem:
There are two lists: C=[i,i,k,l,i] and D =[m,n,o,p,q]
I want to select the index of the minimum element of C. If k or l is the minimum, it is quite simple, since the min function will directly return the desired index. But if i is the minimum, there are several possibilities. In that case, I want to look at list D's elements, but only at the indices where i occurs in C. I then want to chose my sought-after index based on the minimum of those particular elements in D
I thought of the following code:
min_C = min(C)
if C.count(min_C) == 1:
soughtafter_index = C.index(min_C)
else:
possible_D_value = []
for iterate in C:
if iterate==min_C:
possible_index = C.index(iterate)
possible_D_value.append(D[possible_index])
best_D_value = min(possible_D_value)
soughtafter_index = D.index(best_D_value)
(Note that in the problem C and D will always have the same length)
I havent had a chance to test the code yet, but wanted to ask whether it is reasonable? Is there a better way to handle this? (and what if there is a third list-- then this code will get even longer...)
Thank you all
Try this:
soughtafter_index = list(zip(C, D)).index(min(zip(C,D)))
UPDATE with the required explanation:
>>> C = [1, 5, 1, 3, 1, 4]
>>> D = [0, 1, 1, 3, 0, 1]
>>> list(zip(C, D))
[(1, 0), (5, 1), (1, 1), (3, 3), (1, 0), (4, 1)]
>>> min(zip(C, D))
(1, 0)
I have a function,
f(x,y)=4x^2*y+3x+y
displayed as
four_x_squared_y_plus_three_x_plus_y = [(4, 2, 1), (3, 1, 0), (1, 0, 1)]
where the first item in the tuple is the coefficient, the second item is the exponent of x, and the third item is the exponent of y. I am trying to calculate the output at a certain value of x and y
I have tried to split the list of terms up, into what they represent and then feed in the values of x and y when I input them however I am getting unsupported operand type regarding ** tuples - even though I tried to split them up into separate values within the terms
Is this an effective method of splitting up tuples like this of have I missed a trick?
def multivariable_output_at(list_of_terms, x_value, y_value):
coefficient, exponent, intersect = list_of_terms
calculation =int(coefficient*x_value^exponent*y_value)+int(coefficient*x_value)+int(y_value)
return calculation
multivariable_output_at(four_x_squared_y_plus_three_x_plus_y, 1, 1) # 8 should be the output
please try this:
four_x_squared_y_plus_three_x_plus_y = [(4, 2, 1), (3, 1, 0), (1, 0, 1)]
def multivariable_output_at(list_of_terms, x_value, y_value):
return sum(coeff*(x_value**x_exp)*(y_value**y_exp) for coeff,x_exp,y_exp in list_of_terms)
print(multivariable_output_at(four_x_squared_y_plus_three_x_plus_y, 1, 1))
NOTICE:
this is different from how your code originally treated variables, and is based on my intuition of what the list of term means, given your example.
If you have more examples of input -> output, you should check my answer with all of them to make sure what I did is correct.
The first line of code unpacks the list of tuples into three distinct tuples:
coefficient, exponent, intersect = list_of_terms
# coefficient = (4, 2, 1)
# exponent = (3, 1, 0)
# intersect = (1, 0, 1)
The product operator * is not supported by tuples, do you see the issue?
I would like to iterate over all lists/tuples of length n with elements from -s...s. Currently I do this with:
for k in itertools.product(range(-s,s+1), repeat = n):
#process k and maybe print out the result
However this not useful for me as there are a huge number of such tuples and my code may never terminate. I would really like to start with the most interesting ones first. In this case the order I would like for the iteration is:
All tuples that contain only 0 (there is only one)
All tuples that contain only 0, 1 and -1 excluding those tuples we have already seen.
All tuples that contain only 0, 1,-1, 2 and-2 excluding those tuples we have already seen.
And so on...
How can one do this?
How about this:
import itertools
def sorted_tuples(length, max_s):
nums = [0]
for s in range(max_s):
for p in itertools.combinations_with_replacement(nums, length):
if s in p or -s in p:
yield p
nums = [-(s+1)] + nums + [s+1]
for i in sorted_tuples(3,2):
print(i)
# prints the following
(0, 0, 0)
(-1, -1, -1)
(-1, -1, 0)
(-1, -1, 1)
(-1, 0, 0)
(-1, 0, 1)
(-1, 1, 1)
(0, 0, 1)
(0, 1, 1)
(1, 1, 1)
So your code to be done with the lists in much more expensive than sorting?
Then you can sort the list of these lists with a key argument. The things you call list are tuples indeed, right? At least in my python 2.7 itertools. I would convert them to arrays, since I think you cannot use abs otherwise. Then the sorting function is:
lists.sort(key = lambda t: np.max(np.abs(np.array(t))))
does this work fast enough?
I am writing a little optimization tool for purchasing stamps at the post office.
In the process I am using a dictionary, which I am sorting according to what I learned in this other "famous" question:
Sort a Python dictionary by value
In my case my dictionary is mildly more complex:
- one four-item-tuple to make the key
- and another five-item-tuple to make the data.
The origin of this dictionary is an iteration, where each successful loop is adding one line:
MyDicco[A, B, C, D] = eval, post, number, types, over
This is just a tiny example of a trivial run, trying for 75 cents:
{
(0, 0, 1, 1): (22, 75, 2, 2, 0)
(0, 0, 0, 3): (31, 75, 3, 1, 0)
(0, 0, 2, 0): (2521, 100, 2, 1, 25)
(0, 1, 0, 0): (12511, 200, 1, 1, 125)
(1, 0, 0, 0): (27511, 350, 1, 1, 275)
}
So far I am using this code to sort (is is working):
MyDiccoSorted = sorted(MyDicco.items(), key=operator.itemgetter(1))
I am sorting by my evaluation-score, because the sorting is all about bringing the best solution to the top. The evaluation-score is just one datum out of a five-item-tuple (in the example those are the evaluation-scores: 22, 31, 2521, 12511 and 27511).
As you can see in the example above, it is sorting (as I want it) by the second tuple, index 1. But I had to (grumpily) bring my "evaluation-score" to the front of my second tuple. The code is obviously using the entire second-tuple for the sorting-process, which is heavy and not needed.
Here is my question: How can I please sort more precisely. I do not want to sort by the entire second tuple of my dictionary: I want to target the first item precisely.
And ideally I would like to put this value back to its original position, namely to be the last item in the second tuple - and still sort by it.
I have read-up on and experimented with the syntax of operator.itemgetter() but have not managed to just "grab" the "first item of my second item".
https://docs.python.org/3/library/operator.html?highlight=operator.itemgetter#operator.itemgetter
(note: It is permissible to use tuples as keys and values, according to:
https://docs.python.org/3/tutorial/datastructures.html?highlight=dictionary
and those are working fine for my project; this question is just about better sorting)
For those who like a little background (you will yell at me that I should use some other method, but I am learning about dictionaries right now (which is one of the purposes of this project)):
This optimization is for developing countries, where often certain values of stamps are not available, or are limited in stock at any given post office. It will later run on Android phones.
We are doing regular mailings (yes, letters). Figuring out the exact postage for each destination with the available values and finding solutions with low stocks of certain values is a not-trivial process, if you consider six different destination-based-postages and hundreds of letters to mail.
There are other modules which help turning the theoretical optimum solution into something that can actually be purchased on any given day, by strategic dialog-guidance...
About my dictionary in this question:
I iterate over all reasonable (high enough to make the needed postage and only overpaying up to a fraction of one stamp) combinations of stamp-values.
Then I calculate a "success" value, which is based on the number of stamps needed (priority), the number of types needed (lower priority)(because purchasing different stamps takes extra time at the counter) and a very high penalty for paying-over. So lowest value means highest success.
I collect all reasonable "solutions" in a dictionary where the tuple of needed-stamps serves as the key, and another tuple of some results-data makes up the values. It is mildly over-defined because a human needs to read it at this phase in the project (for debugging).
If you are curious and want to read the example (first line):
The colums are:
number of stamps of 350 cents
number of stamps of 200 cents
number of stamps of 50 cents
number of stamps of 25 cents
evaluation-score
calculated applied postage
total number of stamps applied
total number of stamp-types
over-payment in cents if any
Or in words: (Assuming a postal service is offering existing stamps of 350, 200, 50 and 25 cents), I can apply postage of 75 cents by using 1x 50 cents and 1x 25 cents. This gives me a success-rating of 22 (the best in this list), postage is 75 cents, needing two stamps of two different values and having 0 cents overpayment.
You can just use a double index, something like this should work:
MyDiccoSorted = sorted(MyDicco.items(), key=lambda s: s[1][2])
Just set 2 to whatever the index is of the ID in the tuple.
I find it easier to use lambda expressions than to remember the various operator functions.
Assuming, for the moment, that your eval score is the 3rd item of your value tuple (i.e. (post, number, eval, types, over):
MyDiccoSorted = sorted(MyDicco.items(), key=lamba x:x[1][2])
Alternatively, you can create a named function to do the job:
def myKey(x): return x[1][2]
MyDiccoSorted = sorted(MyDicco.items(), key=myKey)
You can use a lambda expression instead of operator.itemgetter() , to get the precise element to sort on. Assuming your eval is the first item in the tuple of values, otherwise use the index of the precise element you want in x[1][0] .Example -
MyDiccoSorted = sorted(MyDicco.items(), key=lambda x: x[1][0])
How this works -
A dict.items() returns something similar to a list of tuples (though not exactly that in Python 3.x) , Example -
>>> d = {1:2,3:4}
>>> d.items()
dict_items([(1, 2), (3, 4)])
Now, in sorted() function, the key argument accepts a function object (which can be lambda , or operator.itemgetter() which also return a function, or any simple function) , the function that you pass to key should accept one argument, which would be the element of the list being sorted.
Then that key function is called with each element, and you are expected to return the correct value to sort the list on. An example to help you understand this -
>>> def foo(x):
... print('x =',x)
... return x[1]
...
>>> sorted(d.items(),key=foo)
x = (1, 2)
x = (3, 4)
[(1, 2), (3, 4)]
does this do what you need?
sorted(MyDicco.items(), key=lambda x: x[1][0])
index_of_evaluation_score = 0
MyDiccoSorted = sorted(MyDicco.items(), key=lambda key_value: key_value[1][index_of_evaluation_score])
Placing your evaluation score back at the end where you wanted it, you can use the following:
MyDicco = {
(0, 0, 1, 1): (75, 2, 2, 0, 22),
(0, 0, 0, 3): (75, 3, 1, 0, 31),
(0, 0, 2, 0): (100, 2, 1, 25, 2521),
(0, 1, 0, 0): (200, 1, 1, 125, 12511),
(1, 0, 0, 0): (350, 1, 1, 275, 27511)}
MyDiccoSorted = sorted(MyDicco.items(), key=lambda x: x[1][4])
print MyDiccoSorted
Giving:
[((0, 0, 1, 1), (75, 2, 2, 0, 22)), ((0, 0, 0, 3), (75, 3, 1, 0, 31)), ((0, 0, 2, 0), (100, 2, 1, 25, 2521)), ((0, 1, 0, 0), (200, 1, 1, 125, 12511)), ((1, 0, 0, 0), (350, 1, 1, 275, 27511))]
I think one of the things you might be looking for is a stable sort.
Sorting functions in Python are generally "stable" sorts. For example, if you sort:
1 4 6
2 8 1
1 2 3
2 1 8
by its first column, you'll get:
1 4 6
1 2 3
2 8 1
2 1 8
The order of rows sharing the same value in column 1 does not change. 1 4 6 is sorted before 1 2 3 because that was the original order of these rows before the column 1 sort. Sorting has been 'stable' since version 2.2 of Python. More details here.
On another note I'm interested in how much you had to explain your code. That is a sign that the code would benefit from refactoring to make its purpose clearer.
Named tuples could be used to remove the hard-to-read tuple indices you see in many answer here, e.g. key=lambda x: x[1][0]-- what does that actually mean? What is it doing?
Here's a version using named tuples that helps readers (most importantly, you!) understand what your code is trying to do. Note how the lambda now explains itself much better.
from collections import namedtuple
StampMix = namedtuple('StampMix', ['c350', 'c200', 'c50', 'c25'])
Stats = namedtuple('Stats', ['score', 'postage', 'stamps', 'types', 'overpayment'])
data = {
(0, 0, 1, 1): (22, 75, 2, 2, 0),
(0, 0, 0, 3): (31, 75, 3, 1, 0),
(0, 0, 2, 0): (2521, 100, 2, 1, 25),
(0, 1, 0, 0): (12511, 200, 1, 1, 125),
(1, 0, 0, 0): (27511, 350, 1, 1, 275)
}
candidates = {}
for stampmix, stats in data.items():
candidates[StampMix(*stampmix)] = Stats(*stats)
print(sorted(candidates.items(), key=lambda candidate: candidate[1].score))
You can see the benefits of this approach in the output:
>>> python namedtuple.py
(prettied-up output follows...)
[
(StampMix(c350=0, c200=0, c50=1, c25=1), Stats(score=22, postage=75, stamps=2, types=2, overpayment=0)),
(StampMix(c350=0, c200=0, c50=0, c25=3), Stats(score=31, postage=75, stamps=3, types=1, overpayment=0)),
(StampMix(c350=0, c200=0, c50=2, c25=0), Stats(score=2521, postage=100, stamps=2, types=1, overpayment=25)),
(StampMix(c350=0, c200=1, c50=0, c25=0), Stats(score=12511, postage=200, stamps=1, types=1, overpayment=125)),
(StampMix(c350=1, c200=0, c50=0, c25=0), Stats(score=27511, postage=350, stamps=1, types=1, overpayment=275))
]
and it will help with your algorithms too. For example:
def score(stats):
return stats.postage * stats.stamps * stats.types + 1000 * stats.overpayment
When i executed the following python script
list= (1,2,3,4,1,2,7,8)
for number in list:
item1= number
item2= list[list.index(item1)+2]
couple= item1, item2
print couple
the goal is to link each number with the second following
I obtain this result
(1, 3)
(2, 4)
(3, 1)
(4, 2)
(1, 3)
(2, 4)
(and then the index gets out of range but this is not the problem)
My question is why the number 1 in the fifth line is still coupled to the number 3 and how can i make that it is coupled to the number 7; idem for the number 2 in the sixth line that should be coupled to the number 8.
additional question
what do I do if i only want to make a list of the couples that start with 1: [(1,3), (1,7)]
list.index returns the offset of the first occurrence of the value in the list - thus if you do [1,1,1].index(1), the answer will always be 0, even though 1 and 2 are also valid answers.
Instead, try:
from itertools import islice, izip, ifilter
mylist = [1,2,3,4,1,2,7,8]
for pair in ifilter(lambda x: x[0]==1, izip(mylist, islice(mylist, 2, None))):
print pair
results in
(1, 3)
(1, 7)
xs.index(x) gives you the index of the first occurence of x in xs. So when you get to the second 1, .index gives you the index of the first 1.
If you need the index alongside the value, use enumerate: for i, number in enumerate(numbers): print number, numbers[i+2].
Note that I deliberately didn't use the name list. It's the name of a built-in, you shouldn't overwrite it. Also note that (..., ...) is a tuple (and therefore can't be changed), not a list (which is defined in square brackets [..., ...] and can be changed).
You have duplicates in the list so index always returns the first index.
Start your program with for index in range(len(list) - 1)
You are using .index which returns the first occurrence of number.
consider:
for number in range(len(list)):
item1= list[number]
item2= list[number+2]
couple= item1, item2
print couple
>>> zip(lst, lst[2:])
[(1, 3), (2, 4), (3, 1), (4, 2), (1, 7), (2, 8)]
To get only pairs (1, X):
>>> [(a, b) for (a, b) in zip(lst, lst[2:]) if a == 1]
[(1, 3), (1, 7)]
Recommended reading:
http://docs.python.org/tutorial/datastructures.html
http://docs.python.org/howto/functional.html