Reputation: 105
For a 2D list [["bacon", "banana"], ["ham", "salami", "cheese"]] I want to iterate through as "bacon", then "banana", then "ham" etc.
sandwiches = [["bacon", "banana"], ["ham", "salami", "cheese"]]
preferences = ["bacon", 5, "ham", -2, "salami", 1]
In the sandwiches array, there are 2 sandwiches, bacon+banana and ham+salami+cheese. I want to know the score for each sandwich by doing something like this (doesn't work but shows what I'd like to do):
sandwichscores = [0 for i in sandwiches]
sandwichscores = [+preferences[preferences.index(j)+1] for j in i in sandwiches if
j in preferences]
But of course for j in i in sandwiches doesn't work. I've tried messing around with the order of the fors and ins but haven't gotten anywhere. How could this be done?
For instance, the output I want here would be:
sandwichscores = [5, -1]
Since the ingredients have a combined score of 5 in the first sandwich and -1 in the second. The ingredients that aren't in the preferences get ignored.
Upvotes: 0
Views: 4963
Reputation: 7859
Here is another way in which you can do it, although I changed the structure of preferences
to dictionary, which is more practical and easier to utilize:
sandwiches = [["bacon", "banana"], ["ham", "salami", "cheese"]]
preferences = {"bacon" : 5, "ham" : -2, "salami" : 1}
scores = [sum(preferences.get(ingredient,0) for ingredient in sandwich) for sandwich in sandwiches]
print(scores)
Output:
[5, -1]
Upvotes: 1
Reputation: 51683
I would use a dictionary for the score lookup - it is the designated datastructure for lookups.
You can go from your representation of preferences
to a dictionary with a dict-comprehension:
preferences = ["bacon", 5, "ham", -2, "salami", 1]
prefs = {k:v for k,v in zip(preferences[::2],preferences[1::2])} # dict-comprehension
This uses zip() to join every 2nd element starting at 0 ["bacon","ham","salami"]
to every 2nd element starting at 1 [5,-2,1]
resulting in a zip-generator of (("bacon,5),("ham",-2),("salami",1))
.
The zip-generator-result is then decomposed into key:value
pairs that create the dict.
With that out of the way, you can calculate your sums like so:
sandwiches = [["bacon", "banana"], ["ham", "salami", "cheese"]]
prefs = {"bacon": 5, "ham": -2, "salami": 1}
score = [ (sandw, sum( prefs.get(ingred,0)
for ingred in sandw))
for sandw in sandwiches ]
print(score)
The score
sums up each ingredients score for each sandwinch you defined. If an ingredient is not found, 0 is added instead.
The output is a tuple of the sandwich and its score:
[(['bacon', 'banana'], 5), (['ham', 'salami', 'cheese'], -1)]
Upvotes: 0
Reputation: 24371
I think this is the logic you want to use, unpacked into a nested for loop:
for i, sandwich in enumerate(sandwiches):
for filling in sandwich:
if filling in preferences:
sandwichscores[i] += preferences[preferences.index(filling)+1]
print(sandwichscores)
>>> [5, -1]
As i alarmed alien says, the logic is much simpler if you use a dictionary for the scores:
preferences = {'bacon':5,'ham':-2,'salami':1}
#...
for i, sandwich in enumerate(sandwiches):
for filling in sandwich:
sandwichscores[i] += preferences.get(filling, 0)
Upvotes: 1
Reputation: 9530
Here is a one-liner that does what you want; I converted your preferences list into a dictionary because that is a much more suitable data structure when you are storing key/value pairs:
sandwiches = [["bacon", "banana"], ["ham", "salami", "cheese"]]
prefs = {"bacon": 5, "ham": -2, "salami": 1}
scores = [ [ ", ".join(i), sum( prefs[j] for j in i if j in prefs) ] for i in sandwiches ]
print(scores)
Output:
[['bacon, banana', 5], ['ham, salami, cheese', -1]]
The solution uses sum
to add up the values of the sandwich ingredients, which are filtered by whether or not the ingredient appears in prefs
.
You can change the output format to remove the list of ingredients and just output the score by altering the [ ", ".join(i), sum( prefs[j] for j in i if j in prefs) ]
part. I would have assumed it was important to know which sandwich got which score, but who knows!
Upvotes: 1
Reputation: 195613
Here's one liner using groupby
:
from itertools import groupby
sandwiches = [["bacon", "banana"], ["ham", "salami", "cheese"]]
preferences = ["salami", 999, "bacon", 5, "ham", -2, "banana", 1000]
l = [(v, sum(i[-1] for i in g)) for v, g in groupby(((sandwich, preferences[preferences.index(p)+1]) for sandwich, prefs in zip(sandwiches, [preferences[::2]] * len(sandwiches)) for p in prefs if p in sandwich), key=lambda v: v[0])]
print(l)
Prints:
[(['bacon', 'banana'], 1005), (['ham', 'salami', 'cheese'], 997)]
For sandwich ['bacon', 'banana']
: Bacon has 5, banana has 1000, sandwich score is 1005
For sandwich ['ham', 'salami', 'cheese']
: Ham has -2, salami has 999, sanwich score is 997
Upvotes: 0