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:
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 theiter
built-in function.Once you have an iterator, you can use it in a
for
statement just like an iterable. In fact, the implementation offor
creates an iterator from a iterable, so you only need to do it yourself if you have some extra need. (If you -- or thefor
loop -- calliter
on an iterator, it returns the iterator itself.)Calling
next
on an iterator returns the next value and advances the iterator. Since thefor
loop is using the same iterator, it won't see the value extracted with the explicit call tonext
.If there is no next element (which would be an input error),
next
will raiseStopIteration
, but that will not cause thefor
loop to quietly terminate; that only happens ifStopIteration
is raised while thefor
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 atry
statement and throw a more meaningful exception. I didn't do that because it's a bit of a distraction, but...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 theelif
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] == '@' }