简体   繁体   中英

How do I get the index of the largest element adjacent to the greatest element in a list

So I have stock = [5,6,8,4,8,3,6,4] . I want to get the index of the greatest element adjacent to the 1st occurrence of the greatest element, 8. So what I want to get will be 6 with index 1. I have tried using this code.

closest = min(range(len(stock)), key=lambda i: abs(stock[i]-max(stock)))

but it just returns the max element.

If I understood your problem correctly, the most interesting input would look like [1,5,8,4,8,7,6,4] . Ie we need to return the index of the 5 since it's a second maximum closest to the first occurrence of the maximum. If so, then the algorithm would look as follows:

find two leftmost and absolute maximums m1 and m2
if m1 == m2 then the target is in either of two subarrays:
    [0, pos(m1))
    [pos(m1) + 1, pos(m2))
otherwise, the target is in either of the following subarrays:
    [0, pos(m1))
    [pos(m1) + 1, len(arr))

We can find k max elements in an array in a close to linear time using the binary heap . So, I think I got a linear solution for you:

import heapq

def nlargest_with_pos(n, arr):
    assert len(arr) >= n
    largest = heapq.nlargest(n, ((it[1], -it[0]) for it in enumerate(arr)))
    return [(it[0], -it[1]) for it in largest]

def find_x(arr):
    assert len(arr) > 1

    first_max, second_max = nlargest_with_pos(2, arr)
    if len(arr) == 2:
        return second_max[1]

    left_range = (0, first_max[1])

    if second_max[0] == first_max[0]:
        right_range = (first_max[1] + 1, second_max[1])
    else:
        right_range = (first_max[1] + 1, len(arr))

    left_hand = arr[left_range[0]:left_range[1]]
    right_hand = arr[right_range[0]:right_range[1]]

    if not left_hand:
        return nlargest_with_pos(1, right_hand)[0][1]
    if not right_hand:
        return nlargest_with_pos(1, left_hand)[0][1]

    left_second_max = nlargest_with_pos(1, left_hand)[0]
    right_second_max = nlargest_with_pos(1, right_hand)[0]

    if left_second_max[0] >= right_second_max[0]:
        return left_second_max[1]
    else:
        return right_second_max[1]

print(find_x([1,5,8,4,8,7,6,4]))

Not very pretty, but it will cater for all possible scenarios, ie your list, max value a the start or the end, two or one value list.

Code is:

def highest_neighbour(stock):
    if stock:
        x = stock.index(max(stock))
        if x - 1 >= 0:
            if x + 1 < len(stock):
                if stock[x + 1] > stock[x - 1]:
                    return x + 1
            return x - 1
        elif x + 1 < len(stock):
            return x + 1
        else:
            return -1

I've set it to return -1 if the list only has one entry.

Output is:

highest_neighbour([5,6,8,4,8,3,6,4]) # ->  1
highest_neighbour([5,6,8,4,8,3,6,9]) # ->  6
highest_neighbour([9,6,8,4,8,3,6,4]) # ->  1
highest_neighbour([3,5])             # ->  0
highest_neighbour([8])               # -> -1
highest_neighbour([])                # -> None

Like this:

stock = [5,6,8,7,8,3,6,4]

if stock.index(max(stock)) == len(stock)-1:
    print(len(stock)-2)
elif not stock.index(max(stock)):
    print(1)
elif stock[stock.index(max(stock))-1] > stock[stock.index(max(stock))+1]:
    print(stock.index(max(stock))-1)
else:
    print(stock.index(max(stock))+1)

Output:

1

Not very elegant but this should work nonetheless:

stock.index(max(stock[stock.index(max(stock)) - 1], stock[(stock.index(max(stock)) + 1) % len(stock)]))

You'll have to add handling if there's a chance you see a list with less than three values

def max_neighbor_index(l: list):
    max_number = max(l)
    max_number_indexes = [x for x in range(0, len(l)) if l[x] == max_number]
    result = []
    for number_index in max_number_indexes:
        if number_index == 0:
            result.append(1)
        elif number_index == len(l) - 1:
            result.append(len(l) - 2)
        else:
            result.append(l.index(max([l[number_index - 1], l[number_index + 1]])))
    max_neighbor = max([l[x] for x in result])
    return [x for x in result if l[x] == max_neighbor][0]


stock = [5, 6, 8, 4, 8, 3, 6, 4]
print(max_neighbor_index(stock))
1

This prints index of highest element that's next to the first occurrence of maximum value in list stock :

stock = [1,5,8,4,8,7,6,4]

idx_max = stock.index(max(stock))
print(max([i for i in [idx_max-1, idx_max+1] if -1 < i < len(stock)], key=lambda k: stock[k]))

Prints:

1

Test cases:

stock = [8,3,8,4,8,3,6,4]   # 1
stock = [1,3,1,3,8,5,6,4]   # 5
stock = [1,3,1,4,1,3,6,8]   # 6
stock = [1,5,8,4,8,7,6,4]   # 1

Here's one way:

def get_max_neighbour(l):
    _max = max(l)
    excl = (-1, len(l))
    neighbour = max(
        (
            (l[j], j)
            for i in range(excl[-1])
            for j in (i-1, i+1)
            if l[i] == _max and j not in excl
        ),
        key=lambda x: x[0]
    )
    return neighbour[1]

Result:

1

The nice thing about this is you can return both the value and index if you want.

stock = [5,6,8,4,8,3,6,4]
idx = 1
tmp,nxt = stock[0:2]
for i in range(1, len(stock)):
    buf = stock[i-1] if i == len(stock)-1 else max(stock[i-1], stock[i+1])
    if tmp < stock[i] or (tmp == stock[i] and nxt < buf): 
        idx = stock.index(buf, i-1)
        nxt = stock[idx]
        tmp = stock[i]
print('greatest next to greatest', nxt, 'at', idx)

Here's my solution to this puzzle. I'd say it is most similar to the solution of @DavidBuck, in that [8] -> -1 and [] -> None , but has four fewer exit points:

from math import inf

def index_of_max_neighbor_of_max(array):
    if not array:
        return None

    index = array.index(max(array))
    a = array[index - 1] if index - 1 >= 0 else -inf
    b = array[index + 1] if index + 1 < len(array) else -inf
    return index + (b > a) * 2 - 1

And my test code:

if __name__ == "__main__":

    iomnom = index_of_max_neighbor_of_max

    print(iomnom([5, 6, 8, 4, 8, 3, 6, 4]))  # 1
    print(iomnom([5, 6, 8, 4, 8, 3, 6, 9]))  # 6
    print(iomnom([5, 3]))  # 1
    print(iomnom([3, 5]))  # 0
    print(iomnom([8]))  # -1
    print(iomnom([]))  # None
    print(iomnom([5, 6, 8, 7, 8, 3, 6, 4]))  # 3
    print(iomnom([5, 6, 8, 4, 8, 3, 6, 9]))  # 6
    print(iomnom([5, 4, 8, 6, 8, 3, 6, 4]))  # 3

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