iterate on two dictionaries with list as values

python iterate dictionary key, value
iterate list of dictionaries python
iterate through dictionary python
how to iterate over key, value pairs
key, value in for loop in python
for k, v
python iterate over dictionary values
python iterate list with index

I have data regarding to employees punch time clock.

Employee can report his starting time by an automated process (by his key card or by finger print), or manually through a simple web form.

The problem is that there are employees who accidentally reported time on more than one method

The input stream data comes in two dictionaries with value as list as the following:

I'm trying to iterate on both dictionaries and count (not sum) if employee made login on the specific date.

def count_type(logins, punch_clock_data):
    counter = 0
    ans_dict = {}
    for punch_clock_key, punch_clock_value in punch_clock_data.items():
        for element in punch_clock_value:
            if element not in ans_dict:
                l1 = logins.get(element)
                for i in range(len(l1)):
                    if i == 1:
                        counter+=1
                        break
            ans_dict[punch_clock_key] = counter
        print(f'this employee was at work {counter} days this week by {punch_clock_key} login')
    return ans_dict


# each item in the array is a representation of weekday. for example, 
# on Sunday there was not any log in data.
# on Tuesday, this employee reported login both on web form and by 
# card(flag = 1) etc.


logins = { 'card'        :[0, 1, 1, 0, 0, 0, 0],
           'fingerprint' :[0, 0, 0, 1, 1, 0, 0],
           'web form'    :[0, 0, 1, 1, 0, 1, 1]
}


# dictionary contains data on types of punch clock
punch_clock_data  = { 'automated' :['card', 'fingerprint'],
                      'manual'    :['web form'],
                      'all_types' :['card', 'fingerprint', 'web form']
}

res = count_type(logins, punch_clock_data)
print(res)

My output is not as expected. This is my output

{'automated': 2, 'manual': 3, 'all_types': 6}

But I'm trying to get is:

{'automated': 4, 'manual': 4, 'all_types': 6}
  • automated should be 4 because the are four days where flag equal to 1 (Monday, Tuesday by card and Wednesday, Thursday by fingerprint
  • manual should be 4 because the are four days where flag equal to 1 (Tuesday, Wednesday, Friday, Saturday)
  • all_types should be 6 because the are six days where at least one flag is equal to 1

I think that my problem is that I need to iterate on all of the weekdays list by index, and not by the value. For each day of the week, get the right index and than count it (vertically and not horizontally)

look this code

def count_type(logins, punch_clock_data):
    ans_dict = {}
    for punch_clock_key, punch_clock_value in punch_clock_data.items():
        counter = 0
        tmp_tab = [0] * 7
        for login_key in punch_clock_value:
            for i in range(len(logins[login_key])):
                tmp_tab[i] += logins[login_key][i]
        for day in tmp_tab:
            counter += day > 0
        ans_dict[punch_clock_key] = counter
    return ans_dict

For exemple with all_types, i create a tmp_tab which transform your 3 tab in

[0, 1, 2, 2, 1, 1, 1]

then it's then sum of each col and counter += 1 if value of col is > to 0

How to Iterate Through a Dictionary in Python – Real Python, A closer look at these two outputs shows you that the resulting order is exactly If you use a list comprehension to iterate through the dictionary's values, then  Python | Iterate through value lists dictionary While working with dictionary, we can have a case in which we need to iterate through the lists, which are in the keys of dictionaries. This kind of problem can occur in web development domain.

Looks like you only want to count one login on the days where the employee logged in by more than one method in a specific punch clock category. You could zip the login method lists together for each category and test whether there was a login for any of them.

logins = {'card': [0, 1, 1, 0, 0, 0, 0], 'fingerprint' :[0, 0, 0, 1, 1, 0, 0], 'web form': [0, 0, 1, 1, 0, 1, 1]}
punch_clock_data = { 'automated': ['card', 'fingerprint'], 'manual': ['web form'], 'all_types': ['card', 'fingerprint', 'web form']}

results = {}
for group, keys in punch_clock_data.items():
    results[group] = sum(any(t) for t in zip(*[logins[k] for k in keys]))

print(results) 
# {'automated': 4, 'manual': 4, 'all_types': 6}

Per your comment requesting a version that makes it easier to see the steps involved. Here is a bit of a breakdown.

results = {}
for group, keys in punch_clock_data.items():
    # list of lists of logins for each method in the category
    all_logins = [logins[k] for k in keys]

    # zip all_logins by day of the week
    logins_per_day = zip(*all_logins)

    # add 1 for each day where any of the values in the tuple are not zero
    results[group] = sum(any(t) for t in logins_per_day)

Merging Two Dictionaries, merging two dictionaries, retaining the greatest value among # common keys Recall that iterating over a dictionary will produce each of its keys one-by-one. i in range(len(dicts)): for j in dicts[i]: if not (j in list(merged)): merged[j] = dicts[i][j]  Method #2 : Using next() + dictionary comprehension The combination of these methods can also be used to perform this task. This difference is that it’s a one liner and more efficient as next function uses iterator as internal implementation which are quicker than generic methods.

The key here, you need to SUM login like this, example in all type:

       'card':        [0, 1, 1, 0, 0, 0, 0]
       'fingerprint' :[0, 0, 0, 1, 1, 0, 0]
       'web form'    :[0, 0, 1, 1, 0, 1, 1]
       'all type'    :[0, 1, 1, 1, 1, 1, 1]  total = 6

so you could try this :

NUMBER_OF_DAY = 7
def count_type(logins, punch_clock_data):
    ans_dict = {}
    for punch_clock_key, punch_clock_values in punch_clock_data.items():
        # list of all login
        element_list = [logins[punch_clock_value] for punch_clock_value in punch_clock_values]
        # compute the sum of each day
        # EX:
        # [0, 1, 1, 0, 0, 0, 0] + [0, 0, 0, 1, 1, 0, 0]
        # total equal to = [0, 1, 1, 1, 1, 0, 0]
        total_days = [0] * NUMBER_OF_DAY
        for element in element_list:
            for day_index, is_checked in enumerate(element):
                # if he checked is_checked == 1 else is 0 
                if is_checked:
                    # he checked in day mark this in the total by 1 not by some
                    total_days[day_index] = 1

        # now just some the total of day
        ans_dict[punch_clock_key] = sum(total_days)
    return ans_dict

using zip, zip and list comprehensive will help to reduce the code :

def count_type(logins, punch_clock_data):
    ans_dict = {}
    for punch_clock_key, punch_clock_values in punch_clock_data.items():
        # list of all login
        element_list = [logins[punch_clock_value] for punch_clock_value in punch_clock_values]
        # zip them so when we iterate over them we get a tuple of login of one day in each iteration
        element_list = zip(*element_list)
        total = 0
        for days in element_list:   
           total += any(days) and 1 or 0
        ans_dict[punch_clock_key] = total
    return ans_dict

Now we can simplify the code even more:

  element_list = [logins[punch_clock_value] for punch_clock_value in punch_clock_values]
  element_list = zip(*element_list)

  # to this 
  element_list = zip(*[logins[punch_clock_value] for punch_clock_value in punch_clock_values])

and thanks to the build-in sum:

    total = 0
    for days in element_list:   
       total += any(days) and 1 or 0
    ans_dict[punch_clock_key] = total


    # to this 
    ans_dict[punch_clock_key] = sum(any(days) for days in element_list)

So the final result function:

def count_type(logins, punch_clock_data):
    ans_dict = {}
    for punch_clock_key, punch_clock_values in punch_clock_data.items():
        # list of all login
        element_list = element_list = zip(*[logins[punch_clock_value] for punch_clock_value in punch_clock_values])
        ans_dict[punch_clock_key] = sum(any(days) for days in element_list)
    return ans_dict

How to iterate through a python dictionary, Convert list of tuples(Key,Value) into a dictionary of iteration over containers and An iterator needs to define two methods: iter() and next(). You could also need to iterate through a dictionary in Python with its items sorted by values. You can use sorted() too, but with a second argument called key . The key keyword argument specifies a function of one argument that is used to extract a comparison key from each element you’re processing.

Python 3 Notes: More on for Loops, An alternative is to explicitly instruct the for loop to iterate over the key:value pairs​. The .items() method on a dictionary induces a pseudo-list of (key, value)  Iterate over key value pairs of dictionary using dict.items() dict.items() It returns a iterable View object of all key,value elements in the dictionary. Its backed by original dictionary. Let’s iterate over the list using dict.iter() i.e.

Finding the Intersection of Two Dictionaries, It can be pretty tempting to fall into the trap of just using in , with this list as the righthand side, to test for membership. However, in the first example, you're looping  How to use the Python zip() function for parallel iteration How to create dictionaries on the fly using zip() Free Bonus: 5 Thoughts On Python Mastery , a free course for Python developers that shows you the roadmap and the mindset you'll need to take your Python skills to the next level.

20. Dictionaries, If we wanted to find a value associated with a key, we would have to iterate Another way to create a dictionary is to provide a list of key:value pairs using the Whenever two variables refer to the same object, changes to one affect the other. Python | Ways to create a dictionary of Lists Till now, we have seen the ways to creating dictionary in multiple ways and different operations on the key and values in dictionary . Now, let’s see different ways of creating a dictionary of list.

Comments
  • You never reset the value counter. So if you pause at the end of each loop, you would get counter = 2 after looping through both types of automated login, then counter = 3 when you add the manual login, and then counter = 6 when looping through all three values in all_types.
  • nice!! is there a way to write it "less" elegant. In order to see the logic behind it?
  • @Merdok - added a version with a bit of a breakdown of the steps. Let me know if there are any particular spots that still seem confusing.
  • sum(1 for t in zip(*[logins[k] for k in keys]) if any(t)) can just be sum(any(t) for t in zip(*[logins[k] for k in keys])) since the OP is just working with 0s and 1s.