Home > Software design >  How I can store in keys and values in a dictionary when iterating?
How I can store in keys and values in a dictionary when iterating?

Time:10-03

I have a list like this:

my_list = ['@F1', 'OBCD', '!', '@F2', 'ADDAB', '!', '@F3', 'OKKA', '!']

I want it to become a dictionary like this:

{'@F1': 'OBCD', '@F2': 'ADDAB', '@F3': 'OKKA'}

However I'm stuck on this:

my_dict = {}
for i in my_list:
    if i[0] != '@' and i[0].isalpha() == False:
        #pass
    else:
        my_dict[i] = my_list.next(i)

I know the .next(i) doesn't work but I'm basically trying to say "get that i that comes after.

If someone has a solution, could you please keep it iterative and elaborate, because I get lost with those very concatenated responses that have a bunch of stuff going on.

CodePudding user response:

You can use enumerate() to generate the indexes to allow you to access the 'next' item in the list:

my_list = ['@F1', 'OBCD', '!', '@F2', 'ADDAB', '!', '@F3', 'OKKA', '!']

my_dict = {}
for idx,item in enumerate(my_list):
    if item[0] == '@':
        my_dict[item] = my_list[idx 1]

print(my_dict)

Output as requested.

Note that this relies on your current format of '@' denoting the key and there always being another element to be the value.

CodePudding user response:

Use enumerate(). This will return the items as well as indexes. It iterates through the list, uf it sees @ in that item it will store the next item with that string as index.

So your code will look like this -

my_list = ['@F1', 'OBCD', '!', '@F2', 'ADDAB', '!', '@F3', 'OKKA', '!']

# expected: {'@F1': 'OBCD', '@F2': 'ADDAB', '@F3': 'OKKA'}
my_dict = {}

for indx, item in enumerate(my_list):
    if '@' in item:
        my_dict[item] = my_list[indx 1]

print(my_dict)

Result

{'@F1': 'OBCD', '@F2': 'ADDAB', '@F3': 'OKKA'}

If you want to be as sure that the index string has to start with @ then

for indx, item in enumerate(my_list):
    if item[0] == '@':
        my_dict[item] = my_list[indx 1]

Hope this helps. Happy Coding!

CodePudding user response:

It's clear that you don't have to check explicitly for '!' because the list data are in groups of 3. Therefore:

my_list = ['@F1', 'OBCD', '!', '@F2', 'ADDAB', '!', '@F3', 'OKKA', '!']

my_dict = {my_list[i]: my_list[i 1] for i in range(0, len(my_list), 3)}

print(my_dict)

Output:

{'@F1': 'OBCD', '@F2': 'ADDAB', '@F3': 'OKKA'}

CodePudding user response:

Here's how you can do it with next.

def make_dict(lst):
    it = iter(lst)           # Note 1
    d = {}
    for k in it:             # Note 2
        if k[0] == '@':
            d[k] = next(it)  # Notes 3, 4
        elif k != '!':       # Note 5 
            raise ValueError(f"Expected '!' but received {k}")
    return d

Explanatory Notes:

  1. In order to use next, you need an actual iterator, not just an object which can be iterated (like a list). To get an iterator from an iterable, you use the iter built-in function.

  2. Once you have an iterator, you can use it in a for statement just like an iterable. In fact, the implementation of for creates an iterator from a iterable, so you only need to do it yourself if you have some extra need. (If you -- or the for loop -- call iter on an iterator, it returns the iterator itself.)

  3. Calling next on an iterator returns the next value and advances the iterator. Since the for loop is using the same iterator, it won't see the value extracted with the explicit call to next.

  4. If there is no next element (which would be an input error), next will raise StopIteration, but that will not cause the for loop to quietly terminate; that only happens if StopIteration is raised while the for loop is trying to get the next value. StopIteration is not a very useful error indication; it would probably be better to catch the exception with a try statement and throw a more meaningful exception. I didn't do that because it's a bit of a distraction, but...

  5. This code does attempt to raise a meaningful exception if there is something other than ! following a key/value pair. You might be happy to just discard the extra item without producing an error message (depending on your expected input), in which case you could just remove the elif and following statement.

Appendix: a non-iterative solution, even though it was explicitly unrequested:

d = { k: next(it) for it in [iter(my_list)] for k in it if k[0] == '@' }
  • Related