0

Say I have an empty dictionary that a user adds an arbitrary number of items into. After the user adds items to the dictionary, I want to then loop through that dictionary and be able to pull values out of it. What is the best way to access the items in the dictionary since I don't know the name of the key?

For example say I have the following:

# my shopping cart that starts off empty
shopping_cart = {}

# user enters how many items they will have in the cart total
total_items = input("How many items will you add to your cart? ")

# User adds both the value and the key of each item to add
for i in total_items:
    name = input("Enter name of item to add: ")
    location = input("Is the item in front, middle, or back of cart? ")

    shopping_cart[name] = location

At this point I have a shopping_cart dictionary, but I don't have a way to know what the KEYs or VALUEs are.

..... Now say there is some large string of thousands of characters in random order called random_string. It looks like "axdfebzsdcdslapplefjdkslazpair....." Notice how the string is random, but periodically there are names of items like "apple" and "pair".

What I want to do is loop my shopping_cart dictionary and find the next index position within my random_string where the item in my shopping_cart appears.

For example - let's say the user adds 3 items to the shopping cart. The items are "donkey", "apple", "pair".

What I want to do is read through the random_string in order, and return the dictionary value that appears next in the string. I.E. in this case, "apple" is the next item in the random string, so it should be returned so I can lookup the value of "apple" in the dictionary and get the location of the item.

I have working code to do everything that is necessary EXCEPT for knowing how to pull the Keys out of the dictionary. I've copied a line below that essentially shows what I'm trying to accomplish. The problem is I don't know what DICT_KEY is, because it was added by the user.

index = random_string.find([DICT_KEY], index)

........ Not to confuse things, but I'm considering making an empty list that mirrors the dictionary values. In other words, when the user adds the item "apple" to the dictionary, I could add it to the dictionary and to the list. That way I can lookup the item in the dictionary by using it's index position in the list. seems like a bad way to handle this though, so happy to get any advice you can offer...

As you can see, I'm new at this!

occvtech
  • 453
  • 3
  • 10
  • 1
    `list(my_dict)` gives you a list of keys... or just loop directly: `for x in my_dict: do_stuff(x)`, x will be the keys. It sounds like you don't want a dictionary at all, if you want to loop through it. That *defeats the entire purpose of a dictionary*. – juanpa.arrivillaga Sep 28 '17 at 19:39
  • I think you might be right that I shouldn't use a dictionary here... But how can I then relate a secondary value with it? I.E. in the example above I want to know what location each item should be in. Is there a way to accomplish a "link" between those two values in a better way than a dictionary? Thanks! – occvtech Sep 28 '17 at 19:49
  • Use two lists, that have that correspondance by index, or use a list of `tuple`s. – juanpa.arrivillaga Sep 28 '17 at 19:50

1 Answers1

1
>>> a={'apple':'front','donkey':'middle','pair':'back'}
>>> s='asdfhskdfksjdf;ksjapplefsakdjfskdjfapplesdfksdjdonkeydlkfjsldjfdpair'
>>> {k:[m.start() for m in re.finditer(k,s)] for k in a}
{'pair': [64], 'donkey': [47], 'apple': [18, 35]}

This one found two apple, one donkey and one pair in the string at indices 18/35/47/64.


Explanation
Follow up on the commands used earlier

Create a new dictionary with the keys I have and assign a constant value.

>>> a
{'pair': 'back', 'donkey': 'middle', 'apple': 'front'}
>>> {k:0 for k in a}
{'pair': 0, 'donkey': 0, 'apple': 0}

That allows us to make a dictionary with each key having same value 0. a being the dictionary you already made.

Now let's see how we set the values to indices of these words in the big string.

>>> [m.start() for m in re.finditer('apple',s)]
[18, 35]

re.finditer returns as many matches in s for apple.
For each match m thus found, m.start() returns the start index of the match.
Now this gives a list of indices where apple is appearing in the string.

Finally if we combine the above two we get a dictionary with our original keys. And values as a list of indices where they appear in the string.

>>> {k:[m.start() for m in re.finditer(k,s)] for k in a}
{'pair': [64], 'donkey': [47], 'apple': [18, 35]}

UPDATE2
After new req. in comments

>>> d={k:[m.start() for m in re.finditer(k,s)] for k in a}
>>> from collections import defaultdict
>>> nd=defaultdict(list)
>>> for k in d:
...   nd[a[k]].extend(d[k])
... 
>>> dict(nd)
{'front': [18, 35], 'middle': [47], 'back': [64]}

If you do not want to go twice over then..

>>> from collections import defaultdict
>>> nd=defaultdict(list)
>>> for k in a:
...   for m in re.finditer(k,s):
...     nd[a[k]].append(m.start())
... 
>>> dict(nd)
{'front': [18, 35], 'middle': [47], 'back': [64]}

UPDATE3

>>> {(k,a[k]):[m.start() for m in re.finditer(k,s)] for k in a}
{('pair', 'back'): [64], ('apple', 'front'): [18, 35], ('donkey', 'middle'): [47]}
>>> {m.start():(k,a[k]) for k in a for m in re.finditer(k,s)}
{64: ('pair', 'back'), 18: ('apple', 'front'), 35: ('apple', 'front'), 47: ('donkey', 'middle')}

UPDATED

If indices are more important for you then do the below

>>> {m.start():k  for k in a for m in re.finditer(k,s)}
{64: 'pair', 18: 'apple', 35: 'apple', 47: 'donkey'}
kaza
  • 2,317
  • 1
  • 16
  • 25
  • Um.... Yes! This might be exactly what I'm looking for. I will ultimately want to order those values so I can identify which value comes "next" as I act on each in sequence. I don't fully understand what your answer is doing though, so I would REALLY appreciate an explanation. Thanks so much! – occvtech Sep 28 '17 at 19:53
  • @occvtech is the explanation ok? – kaza Sep 28 '17 at 20:36
  • I think I understand. So you create the dictionary `a` just like I did in the OP. Then you create a second dictionary with the same keys as A, but with values set to '0'. Then with some magic I don't fully understand yet, you are able to use a function re.finditer(x,y) to return the locations where each key is found in the string. If I'm mostly understanding correctly, I'll just do some reading on ".start()" and "re.finditer()" to understand better. Otherwise, this looks EXACTLY like what I wanted to do. Thanks so much for the explanation! – occvtech Sep 28 '17 at 20:41
  • 1
    I put a note for `re.finditer()` and `MATCH.start()`. Also if you play with them independently you would be able to understand what is happening. Also this should help [list-comprehension](https://docs.python.org/3/tutorial/datastructures.html#list-comprehensions) and [dictionary-comprehension](https://stackoverflow.com/questions/1747817/create-a-dictionary-with-list-comprehension-in-python) – kaza Sep 28 '17 at 20:53
  • 1
    You are awesome. Thank you so much - I'm off onto testing things now, but not only is this an excellent solution to my problem, but finditer() looks way faster than my old way of using .find()! – occvtech Sep 28 '17 at 23:06
  • Ok, I'm going to complicate this again. More for learnings sake than anything else :). I can now use `re.finditer()` to give me a dictionary containing my required key and it's corresponding values (i.e. list of index positions). However, what if I wanted to return a dictionary containing my original VALUE and it's corresponding index positions? I.E. the original value for `pair` was `back`. Can I create a similar result with re.finditer() that looks up all index positions for the string `back`?. It looks like it is intended to be used for keys only - but fingers crossed! – occvtech Sep 29 '17 at 00:58
  • Let us [continue this discussion in chat](http://chat.stackoverflow.com/rooms/155558/discussion-between-occvtech-and-bulbus). – occvtech Sep 29 '17 at 01:13