Python Forum
Comparing List values to get indexes
Thread Rating:
  • 0 Vote(s) - 0 Average
  • 1
  • 2
  • 3
  • 4
  • 5
Comparing List values to get indexes
#1
I'm trying to compare a short temporary list of values to a master list, to obtain the index number (of short list items) and set two variable values based on the index values being <= 10 or >10.

So when I have an index <=10 set out1 = 1, indexes >10 set out2 value to 1.
If no <=10 index values found, out1 = 0, no index values for >10, out2 = 0.

Here's my code that outputs: out1: 1, out2: 1, but expected out1: 1, out2: 0 based on the example list values.
(if the onList[] is empty during use, the zoneRefresh() function won't be called.)

aList = ["Bin 1", "Bin 2", "Bin 3", "Bin 4", "Bin 5","Bin 6", "Bin 7", "Bin 8", "Bin 9", "Bin 10", "Bin 11",
        "Bin 12", "Bin 13", "Bin 14", "Bin 15"]
onList = ["Bin 3", "Bin 4"] #For test, usually empty
  
def zoneRefresh():
    out1 = 0
    out2 = 0
    for i in range(len(aList)):
        if aList[i] in onList:
            if(i) <= 10:
                out1 = 1
                print("out1: " + str(out1))
            else: # (i) > 10
                out2 = 1
                print("out2: " + str(out2))
I can't see why the out2 varible is assigned a "1" when there is no value with an index greater-than 10 in the onList[].
Any assistance appreciated.
Reply
#2
The only print statements are in a conditional when they are set to 1. So you will never see anything that says it is 0.

You're printing every time it's set to 1, not just at the end. I think your output is not out2 set to 1, but out1 set to 1 twice.

Get rid of the print statements inside the loop. Put them after the end of the for loop.
Reply
#3
Thanks bowlofred, I fixed it.

Please excuse my rookie code
aList = ["Bin 1", "Bin 2", "Bin 3", "Bin 4", "Bin 5","Bin 6", "Bin 7", "Bin 8", "Bin 9", "Bin 10", "Bin 11",   # <=10, 0-10
             "Bin 12", "Bin 13", "Bin 14", "Bin 15"]   # > 10 items,  11-15
onList = ["Bin 3", "Bin 14"] #For test, usually empty

def zoneRefresh():
    out1 = 0
    out2 = 0
    for i in range(len(aList)):
        if aList[i] in onList:
            if(i) <= 10:
                out1 = 1
            else: # (i) > 10
                if(i) > 10:
                    out2 = 1
    print ("out1: " + str(out1) + ", out2: " + str(out2))
Reply
#4
Let me paraphase:
out1 = 1 if any bin from Bin 1 to Bin 11 appears in onList, otherwiise out1 = 0
out2 = 1 if any bin from Bin 12 to Bin 15 is in onList, otherwiise out2 = 0
print out1 and out2

is that correct? If so, that is not what your code does.

To start with, your code only prints if onList is not empty. You have a comment that says this is the normal condition, so normally there will be no printing.

Another problem is that your logic for setting out1 or out2 to zero is wrong. You start out great, doing this:
out1 = 0
out2 = 0
But then you screw it up here:
if(i) <= 10:
     out1 = 1
else: # (i) > 10
    out1 = 0
If onList = ["Bin 2", "Bin 12"], out1 will be set to 1 when your program tests "Bin 2" and it is set to 0 when your program tests "Bin 12". I would expect out1 == 1 (for Bin 2) and out2 == 1 (for Bin 12). Your test was inadequate, checking only one scenario. You should test if the code worked for an empty onList, and write tests for all the boundary conditions.

Your code is not Pythonic. In Python, if your program uses array indexing it usually means the solution is not efficient. Looping in Python is one of the least efficient things you can do. When you are looping, almost all the code is executing in the Python interpreter. This is relatively slow because not only is your program executing the code you wrote, but it is executing an interpreter to execute the code you wrote. Your programs will be much faster (as well as shorter) if you let the Python classes do most of your work. When you use the built in classes (and standard libraries), much of the code execution happens in C libraries. This can be thousands of times faster than running similar code in Python. The built in classes and standard libaries are also highly optimized, so even if they are running some Python code in the interpreter, they will do it more efficiently than code that you or I would write.

If I was writing this code I would avoid the loop and use slices and sets. My program would split the bin list into zones. From your example, zone 1 contains Bin 1 to Bin 11, and zone 2 contains Bin 12 to Bin 15. To determine if a bin in zone 1 is on, I check the interesection of bins in zone 1 and bins in the onList. This is done most efficiently using sets.

A set is an unordered list that supports set operations (intersection, union, difference, complement). To determine if any bin on zone 1 is in the on list, I check if the intersection of zone1 and onList is not empty.
onList = {"Bin 2", "Bin 12"}  # This is a set literal
zone1 = {"Bin 1", "Bin 2", "Bin 3"}
intersection = onList & zone1
value = int(bool(intersection))  # bool(intersection) is False for empty set, else True.  int(True) == 1, int(False) == 0
print(intersection, value)
Output:
{'Bin 2'} 1
Here is your code (I think) using slices and sets.
bins = [f"Bin {i}" for i in range(1, 16)]
zones = [set(bins[:11]), set(bins[11:])]


def zoneRefresh(on_bins):
    """Return 0 or 1 for each zone.  The zone is 1 if any bin
    in that zone is in the on list, else zero.
    """
    on_bins = set(on_bins)
    return [int(bool(zone & on_bins)) for zone in zones]


def test(on_bins):
    print(f"{on_bins} = {zoneRefresh(on_bins)}")


test([])
test(["Bin 11"])
test(["Bin 12"])
test(["Bin 5", "Bin 11"])
test(["Bin 5", "Bin 12"])
test(["Bin 11", "Bin 15"])
test(["Bin 12", "Bin 15"])
I added some tests cases to verify it works correctly.
Output:
[] = [0, 0] ['Bin 11'] = [1, 0] ['Bin 12'] = [0, 1] ['Bin 5', 'Bin 11'] = [1, 0] ['Bin 5', 'Bin 12'] = [1, 1] ['Bin 11', 'Bin 15'] = [1, 1] ['Bin 12', 'Bin 15'] = [0, 1]
The update function creates a set and does set operation. This is far fewer operations than you performed in your program, and each of the operations in my program will be performed in compiled C code, not in interpreted Python. My code is also more flexible. If I wanted three zones instead of two, the only change I need to make is where the zones list is constructed.
zones = [set(bins[:6]), set(bins[6:11]), set(bins[11:])]  # Make three zones.
[] = [0, 0, 0]
['Bin 11'] = [0, 1, 0]
['Bin 12'] = [0, 0, 1]
['Bin 5', 'Bin 11'] = [1, 1, 0]
['Bin 5', 'Bin 12'] = [1, 0, 1]
['Bin 11', 'Bin 15'] = [0, 1, 1]
['Bin 12', 'Bin 15'] = [0, 0, 1]
Reply
#5
Dean,
That is correct.

I figured it out using:

def zoneRefresh():
    out1 = 0
    out2 = 0
    for i in range(len(aList)):
        if aList[i] in onList:
            if(i) <= 10:
                out1 = 1
            else: # (i) > 10
                if(i) > 10:
                    out2 = 1
    print ("out1: " + str(out1) + ", out2: " + str(out2))
This works with all scenarios of <=10 or >10 it seems.
Reply
#6
Close, but not quite right.
def zoneRefresh():
    out1 = 0
    out2 = 0
    for i in range(len(aList)):
        if aList[i] in onList:
            if(i) <= 10:
                out1 = 1
            else:
                out2 = 1
    print ("out1: " + str(out1) + ", out2: " + str(out2))
The extra if statement was not an error, but it was not needed. I think extra code is worse than an error. Errant code should be caught during development or testing. You find the error, fix the error, problem solved. Extra code is a time bomb waiting to cause problems when you later modify your code. The lurking time bomb time errors are hard to find because you assume any errors must be in code that was added, not code that was broken by the update.
Another way to write that gets rid of the indexing.
def zoneRefresh():
    out1 = 0
    out2 = 0
    for index, value in enumerate(aList):
        if value in onList:
            if index <= 10:
                out1 = 1
            else:
                out2 = 1
    print (f"out1: {out1}, out2: {out2}")
Edward_ likes this post
Reply
#7
Thanks Dean,
Can you explain for me the "f" in
print (f"out1: {out1}, out2: {out2}")
Reply
#8
(Jun-09-2023, 01:24 PM)Edward_ Wrote: Can you explain for me the "f" in
print (f"out1: {out1}, out2: {out2}")
https://docs.python.org/3/tutorial/inputoutput.html
Reply


Possibly Related Threads…
Thread Author Replies Views Last Post
  Copying the order of another list with identical values gohanhango 7 1,171 Nov-29-2023, 09:17 PM
Last Post: Pedroski55
  Search Excel File with a list of values huzzug 4 1,265 Nov-03-2023, 05:35 PM
Last Post: huzzug
  Adding values with reduce() function from the list of tuples kinimod 10 2,677 Jan-24-2023, 08:22 AM
Last Post: perfringo
  user input values into list of lists tauros73 3 1,076 Dec-29-2022, 05:54 PM
Last Post: deanhystad
  Replace columns indexes reading a XSLX file Larry1888 2 996 Nov-18-2022, 10:16 PM
Last Post: Pedroski55
  AttributeError: 'list' object has no attribute 'values' ilknurg 4 15,025 Jan-19-2022, 08:33 AM
Last Post: menator01
  Need to parse a list of boolean columns inside a list and return true values Python84 4 2,125 Jan-09-2022, 02:39 AM
Last Post: Python84
  List of dataframe values beginning with x,y or z glidecode 3 1,949 Nov-08-2021, 10:16 PM
Last Post: glidecode
  How to pass list of values to a API request URL chetansaip99 0 3,537 Sep-28-2021, 07:37 AM
Last Post: chetansaip99
  Python dictionary with values as list to CSV Sritej26 4 3,029 Mar-27-2021, 05:53 PM
Last Post: Sritej26

Forum Jump:

User Panel Messages

Announcements
Announcement #1 8/1/2020
Announcement #2 8/2/2020
Announcement #3 8/6/2020