Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

How to multiply dictionary values with other values based on the dictionary's key?

749 views
Skip to first unread message

giannis.d...@gmail.com

unread,
Aug 18, 2018, 7:17:11 PM8/18/18
to
I have the results of an optimization run in the form found in the following pic: https://i.stack.imgur.com/pIA7i.jpg.

How can I multiply the dictionary values of the keys FEq_(i,_j,_k,_l) with preexisting values of the form A[i,j,k,l]?

For example I want the value of key 'FEq_(0,_0,_2,_2)' multiplied with A[0,0,2,2], the value of key 'FEq_(0,_0,_4,_1)' multiplied with A[0,0,4,1] etc. for all the keys present in my specific dictionary.

I have been trying to correspondingly multiply the dictionary values in the form of
varsdict["FEq_({0},_{1},_{2},_{3})".format(i,j,k,l)]

but this is not working as the indexes do not iterate consequently over all their initial range values, they are the results of the optimization so some elements are missing. I also could not find something of a similar nature where I looked.

Thank you for the help!

MRAB

unread,
Aug 18, 2018, 8:01:54 PM8/18/18
to
Iterate over the keys in varsdict and, for each key, extract the indexes.

With an example:

>>> key = 'FEq_(0,_0,_2,_2)'
>>> key
'FEq_(0,_0,_2,_2)'
>>> key.split('(')[1]
'0,_0,_2,_2)'
>>> key.split('(')[1].split(')')[0]
'0,_0,_2,_2'
>>> key.split('(')[1].split(')')[0].split(',_')
['0', '0', '2', '2']

Now convert them to ints and assign to variables:

>>> i, j, k, l = map(int, key.split('(')[1].split(')')[0].split(',_'))

Now you can get A[i,j,k,l].

Steven D'Aprano

unread,
Aug 18, 2018, 9:53:39 PM8/18/18
to
On Sat, 18 Aug 2018 16:16:54 -0700, giannis.dafnomilis wrote:

> I have the results of an optimization run in the form found in the
> following pic: https://i.stack.imgur.com/pIA7i.jpg.

Unless you edit your code with Photoshop, why do you think a JPEG is a
good idea?

That discriminates against the blind and visually impaired, who can use
screen-readers with text but can't easily read text inside images, and
those who have access to email but not imgur.

For the record, here's the table:

Key Type Size Value
FEq_(0,_0,_0,_0) float 1 1.0
FEq_(0,_0,_1,_1) float 1 1.0
FEq_(0,_0,_2,_2) float 1 1.0
FEq_(0,_0,_3,_0) float 1 1.0
FEq_(0,_0,_4,_1) float 1 1.0


It took me about 30 seconds to copy out by hand from the image. But what
it means is a complete mystery. Optimization of what? What you show isn't
either Python code or a Python object (like a dict or list) so it isn't
any value to us.


> How can I multiply the dictionary values of the keys FEq_(i,_j,_k,_l)
> with preexisting values of the form A[i,j,k,l]?
>
> For example I want the value of key 'FEq_(0,_0,_2,_2)' multiplied with
> A[0,0,2,2], the value of key 'FEq_(0,_0,_4,_1)' multiplied with
> A[0,0,4,1] etc. for all the keys present in my specific dictionary.


Sounds like you have to parse the key for the number fields:

- extract out the part between the parentheses '0,_0,_2,_2'

If you know absolutely for sure that the key format is ALWAYS going to be
'FEq_(<fields>)' then you can extract the fields using slicing, like this:

key = 'FEq_(0,_0,_2,_2)'
fields = key[5, -1] # cut from char 5 to 1 back from the end

If you're concerned about that "char 5" part, it isn't an error. Python
starts counting from 0, not 1, so char 1 is "E" not "F".



- delete any underscores
- split it on commas
- convert each field to int
- convert the list of fields to a tuple

fields = fields.replace('_', '')
fields = string.split(',)
fields = tuple([int(x) for x in fields])


and then you can use that tuple as the key for A.

It might be easier and/or faster to convert A to use string keys
"FEq_(0,_0,_2,_2)" instead. Or, depending on the size of A, simply make a
copy:

B = {}
for (key, value) in A.items():
B['FEq(%d,_%d,_%d,_%d)' % key] = value


and then do your look ups in B rather than A.


> I have been trying to correspondingly multiply the dictionary values in
> the form of
> varsdict["FEq_({0},_{1},_{2},_{3})".format(i,j,k,l)]
>
> but this is not working as the indexes do not iterate consequently over
> all their initial range values, they are the results of the optimization
> so some elements are missing.

I don't see why the dictionary lookup won't work just because the indexes
aren't consistent. When you look up

varsdict['FEq_(0,_0,_2,_2)']

it has no way of knowing whether or not 'FEq_(0,_0,_1,_2)' previously
existed. I think you need to explain more of what you are doing rather
than just dropping hints.

*Ah, the penny drops* ...


Are you trying to generate the keys by using nested loops?

for i in range(1000): # up to some maximum value
for j in range(1000):
for k in range(1000):
for l in range(1000):
key = "FEq_({0},_{1},_{2},_{3})".format(i,j,k,l)
value = varsdict[key] # this fails


That's going to be spectacularly wasteful if the majority of keys don't
exist. Rather, you should just iterate over the ones that *do* exist:

for key in varsdict:
...



--
Steven D'Aprano
"Ever since I learned about confirmation bias, I've been seeing
it everywhere." -- Jon Ronson

giannis.d...@gmail.com

unread,
Aug 19, 2018, 6:15:46 AM8/19/18
to
Thank you MRAB!

Now I can get the corresponding dictionary value A[i,j,k,l] for each key in the varsdict dictionary.

However how would I go about multiplying the value of each FEq_(i,_j,_k,_l) key with the A[i,j,k,l] one? Do you have any insight in that?

giannis.d...@gmail.com

unread,
Aug 19, 2018, 6:35:38 AM8/19/18
to
On Sunday, August 19, 2018 at 3:53:39 AM UTC+2, Steven D'Aprano wrote:

>
> Unless you edit your code with Photoshop, why do you think a JPEG is a
> good idea?
>
> That discriminates against the blind and visually impaired, who can use
> screen-readers with text but can't easily read text inside images, and
> those who have access to email but not imgur.

Thank you very much for the answer Steven! To be honest I did not think of that, I just assumed that it was easier for everyone to just look at the jpeg and see my dictionary. I will keep it in mind for the future.


> Sounds like you have to parse the key for the number fields:
>
> - extract out the part between the parentheses '0,_0,_2,_2'
>
> If you know absolutely for sure that the key format is ALWAYS going to be
> 'FEq_(<fields>)' then you can extract the fields using slicing, like this:
>
> key = 'FEq_(0,_0,_2,_2)'
> fields = key[5, -1] # cut from char 5 to 1 back from the end
>
> If you're concerned about that "char 5" part, it isn't an error. Python
> starts counting from 0, not 1, so char 1 is "E" not "F".
>
>
>
> - delete any underscores
> - split it on commas
> - convert each field to int
> - convert the list of fields to a tuple
>
> fields = fields.replace('_', '')
> fields = string.split(',)
> fields = tuple([int(x) for x in fields])
>
>
> and then you can use that tuple as the key for A.

When I try to this, I get the message 'fields = key[5, -1]. TypeError: string indices must be integers'.

> It might be easier and/or faster to convert A to use string keys
> "FEq_(0,_0,_2,_2)" instead. Or, depending on the size of A, simply make a
> copy:
>
> B = {}
> for (key, value) in A.items():
> B['FEq(%d,_%d,_%d,_%d)' % key] = value
>
>
> and then do your look ups in B rather than A.

This helped me a lot! Now I have 2 dictionaries that contain the same keys and the different values I want to multiply, varsdict and B. However if I try to multiply them using:

{k : v * varsdict[k] for k, v in B.items() if k in varsdict}

or

for key in varsdict:
if key in B:
print(int(varsdict[key]) * int(B[key]))

all I get is an empty dictionary. Do you know how to make this work?


> I don't see why the dictionary lookup won't work just because the indexes
> aren't consistent. When you look up
>
> varsdict['FEq_(0,_0,_2,_2)']
>
> it has no way of knowing whether or not 'FEq_(0,_0,_1,_2)' previously
> existed. I think you need to explain more of what you are doing rather
> than just dropping hints.
>
> *Ah, the penny drops* ...
>
>
> Are you trying to generate the keys by using nested loops?
>
> for i in range(1000): # up to some maximum value
> for j in range(1000):
> for k in range(1000):
> for l in range(1000):
> key = "FEq_({0},_{1},_{2},_{3})".format(i,j,k,l)
> value = varsdict[key] # this fails
>
>
> That's going to be spectacularly wasteful if the majority of keys don't
> exist. Rather, you should just iterate over the ones that *do* exist:
>
> for key in varsdict:
> ...

The varsdict dictionary was the result of the optimization run in PulP and contains the 'prob.variables()' keys and values. so while my initial problem variables were created for all i,j,k,l that I wanted, only the 5 appear in the optimization results.

Now, however I want to multiply the result variables with external dictionary values that were also created for all the i,j,k,l that I wanted. My B dictionary has a length of 150 but I only want the 5 values with the same keys as the varsdict dictionary to be multiplied with the values in the varsdict dictionary correspondigly.

For 5 key/value pairs I can do it manually but for a more complex problem with hundreds of key/value pairs it will be impossible so I am looking to automate that.

Sorry if that reads confusingly, I just started with python and I am trying to explain as clear as I can.

Steven D'Aprano

unread,
Aug 19, 2018, 7:42:29 AM8/19/18
to
Do you want to modify the varsdict values in place?

varsdict['Feq_(i,_j,_k,_l)'] *= A[i,j,k,l]

which is a short-cut for this slightly longer version:

temp = varsdict['Feq_(i,_j,_k,_l)'] * A[i,j,k,l]
varsdict['Feq_(i,_j,_k,_l)'] = temp



If you want to leave the original in place and do something else with the
result:

result = varsdict['Feq_(i,_j,_k,_l)'] * A[i,j,k,l]
print(result)

Steven D'Aprano

unread,
Aug 19, 2018, 7:53:42 AM8/19/18
to
On Sun, 19 Aug 2018 03:35:24 -0700, giannis.dafnomilis wrote:

> On Sunday, August 19, 2018 at 3:53:39 AM UTC+2, Steven D'Aprano wrote:
[...]

>> If you know absolutely for sure that the key format is ALWAYS going to
>> be 'FEq_(<fields>)' then you can extract the fields using slicing, like
>> this:
>>
>> key = 'FEq_(0,_0,_2,_2)'
>> fields = key[5, -1] # cut from char 5 to 1 back from the end
[...]
>> - delete any underscores
>> - split it on commas
>> - convert each field to int
>> - convert the list of fields to a tuple
>>
>> fields = fields.replace('_', '')
>> fields = string.split(',)
>> fields = tuple([int(x) for x in fields])
>>
>>
>> and then you can use that tuple as the key for A.
>
> When I try to this, I get the message 'fields = key[5, -1]. TypeError:
> string indices must be integers'.

Ouch! That was my fault, sorry, it was a typo. You need a colon, not a
comma. Sorry about that!

Try this instead:

key = 'FEq_(0,_0,_2,_2)'
fields = key[5:-1]
fields = fields.replace('_', '')
fields = fields.split(',')
fields = tuple([int(x) for x in fields])
print(fields)


which this time I have tested.


(More comments later, time permitting.)
Message has been deleted

giannis.d...@gmail.com

unread,
Aug 19, 2018, 8:29:59 AM8/19/18
to
Thanks again for your answers Steven. I will try to explain it simpler because I think I tend to complicate things.

With your help I have arrived at this point:
I have the dictionary varsdict (size 5) as below
Key Type Size Value
FEq_(0,_0,_0,_0) float 1 1.0
FEq_(0,_0,_1,_1) float 1 1.0
FEq_(0,_0,_2,_2) float 1 1.0
FEq_(0,_0,_3,_0) float 1 1.0
FEq_(0,_0,_4,_1) float 1 1.0

and the dictionary B (size 150) as below
Key Type Size Value
FEq_(0,_0,_0,_0) float 1 1500.0
FEq_(0,_0,_0,_1) int 1 0
...
FEq_(0,_0,_1,_1) float 1 3300.0
...
FEq_(0,_0,_2,_2) float 1 2200.0
...
FEq_(0,_0,_4,_1) float 1 4000.0

for dictionary B the i,j,k,l ranges run as far as my input ranges when I started the model. So now I only want to multiply the values with the same keys with each other and get the sum of it.

result = Sum(varsdict['FEq_(i,_j,_k,_l)']*B['FEq_(i,_j,_k,_l)']

As I mentioned above I have been trying this with
{k : v * B[k] for k, v in varsdict.items() if k in B}

or

for key in varsdict:
if key in B:
print(int(varsdict[key]) * int(B[key]))

but all I get is an empty dictionary.

Steven D'Aprano

unread,
Aug 19, 2018, 8:37:28 PM8/19/18
to
On Sun, 19 Aug 2018 05:29:46 -0700, giannis.dafnomilis wrote:

> With your help I have arrived at this point: I have the dictionary
> varsdict (size 5) as below
>
> Key Type Size Value
> FEq_(0,_0,_0,_0) float 1 1.0
> FEq_(0,_0,_1,_1) float 1 1.0
> FEq_(0,_0,_2,_2) float 1 1.0
> FEq_(0,_0,_3,_0) float 1 1.0
> FEq_(0,_0,_4,_1) float 1 1.0

That's not a Python dict. It looks like some sort of table structure. How
do you get this? (What menu command do you run, what buttons to you
click, etc?) I'm guessing you are using an IDE ("Integrated Development
Environment") like Anaconda or similar. Is that right?

Python dicts print something like this:

{'FEq_(0,_0,_4,_1)': 9999, 'FEq_(0,_0,_3,_0)': 9999}

If you run

print(varsdict)

what does it show?






(I have limited time to respond at the moment, so apologies for the brief
answers. Hopefully someone else will step in with some help too.)
0 new messages