简体   繁体   中英

(Binary) Summing the elements of a list

I need to sum the elements of a list, containing all zeros or ones, so that the result is 1 if there is a 1 in the list, but 0 otherwise.

def binary_search(l, low=0,high=-1):
    if not l: return -1
    if(high == -1): high = len(l)-1
    if low == high:
        if l[low] == 1: return low
        else: return -1
    mid = (low + high)//2
    upper = [l[mid:high]]
    lower = [l[0:mid-1]]
    u = sum(int(x) for x in upper)
    lo = sum(int(x) for x in lower)
    if u == 1: return binary_search(upper, mid, high)
    elif lo == 1: return binary_search(lower, low, mid-1)
    return -1

 l = [0 for x in range(255)]
 l[123] = 1
 binary_search(l)

The code I'm using to test

u = sum(int(x) for x in upper)

works fine in the interpreter, but gives me the error

TypeError: int() argument must be a string or a number, not 'list'

I've just started to use python, and can't figure out what's going wrong (the version I've written in c++ doesn't work either).

Does anyone have any pointers?

Also, how would I do the sum so that it is a binary xor, not simply decimal addition?

You don't actually want a sum; you want to know whether upper or lower contains a 1 value. Just take advantage of Python's basic container-type syntax:

if 1 in upper:
    # etc
if 1 in lower:
    # etc

The reason you're getting the error, by the way, is because you're wrapping upper and lower with an extra nested list when you're trying to split l (rename this variable, by the way!!). You just want to split it like this:

upper = the_list[mid:high]
lower = the_list[:mid-1]

Finally, it's worth noting that your logic is pretty weird. This is not a binary search in the classic sense of the term. It looks like you're implementing "find the index of the first occurrence of 1 in this list". Even ignoring the fact that there's a built-in function to do this already, you would be much better served by just iterating through the whole list until you find a 1 . Right now, you've got O(nlogn) time complexity (plus a bunch of extra one-off loops), which is pretty silly considering the output can be replicated in O(n) time by:

def first_one(the_list):
    for i in range(len(the_list)):
        if the_list[i] == 1:
            return i
    return -1

Or of course even more simply by using the built-in function index :

def first_one(the_list):
    try:
        return the_list.index(1)
    except ValueError:
        return -1

I need to sum the elements of a list, containing all zeros or ones, so that the result is 1 if there is a 1 in the list, but 0 otherwise.

What's wrong with

int(1 in l)

Stop making nested lists.

upper = l[mid:high]
lower = l[0:mid-1]

I need to sum the elements of a list, containing all zeros or ones, so that the result is 1 if there is a 1 in the list, but 0 otherwise.

No need to sum the whole list; you can stop at the first 1. Simply use any() . It will return True if there is at least one truthy value in the container and False otherwise, and it short-circuits (ie if a truthy value is found early in the list, it doesn't scan the rest). Conveniently, 1 is truthy and 0 is not.

True and False work as 1 and 0 in an arithmetic context (Booleans are a subclass of integers), but if you want specifically 1 and 0, just wrap any() in int() .

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM