计算列表中大于其邻居的数字

Counting the numbers in a list that are larger than their neighbors

我想在列表中找到一个峰。

  1. 我想知道一个数字是否比他的邻居大。
  2. 如果它是列表中的第一个对象,我只想检查他是否比他后面的对象大。
  3. 如果它是列表中的最后一个对象,我想检查他之前的对象。
def peaks(lst):
    num = 0
    leni = len(lst)
    print(leni)
    for i in range(1,leni - 1):
        if  lst[i] > lst[i-1] and lst[i] > lst[i+1]:
                    num = num + 1
    for i in range(leni):
        print(i)
        if i == 0:
            if lst[i] > lst[i+1]:
                num = num + 1
        elif i == leni+1:
            if lst[i] > lst[i-1]:
                num = num + 1
    return num

当它应该检查最后一个对象时,这段代码不起作用。 当我尝试 [1,2,3] 我得到 0 而不是 1.

您好,欢迎来到 Whosebug!

请注意,range(leni) 是一个从 0 到 leni - 1 的数字序列。所以你的条件 i == leni+1 永远不会满足。您可以将其替换为 i == leni - 1.

另请注意,您不需要第二个循环。您可以将其替换为

if lst[0] > lst[1]:
    num = num + 1
if lst[-1] > lst[-2]:
    num= num + 1

此处lst[-1]lst[leni - 1]相同,lst[-2]lst[leni - 2]相同。

应该可以解决问题

def peaks(lst):
  lst_len = len(lst)
  hits = 0
      
  for i in range(1,lst_len-1):
    num_to_test = lst[i]
    before = lst[i-1]
    after = lst[i+1]
    if num_to_test > before and num_to_test > after:
      hits+=1
    # This is for the case lst contains only 1 member and you want to count it as 1
    if lst_len == 1:
      hits+=1
    # For checking the edges 
    if lst_len > 1:
      if lst[0] > lst[1]:
        hits+=1
      if lst[lst_len-1] > lst[lst_len-2]:
        hits+=1

return hits

您可以通过使边界特殊情况不再那么特殊来做一些技巧来计算峰值:

def peaks(lst): 
    lst = [float("-inf")] + lst + [float("-inf")]
    return sum(a < b > c for a, b, c in zip(lst, lst[1:], lst[2:]))

您似乎刚从 python 开始。您的代码很难理解。这个问题有很多可能的解决方案,但我建议编写简单的代码。然后担心性能。

可读性第一!

from typing import List


def peaks(lst: List[int]):
    found = 0

    for i, current_value in enumerate(lst):
        is_first_object = i == 0
        is_last_object = i == len(lst) - 1

        if is_first_object:
            previous_val = None
        else:
            previous_val = lst[i-1]

        if is_last_object:
            next_val = None
        else:
            next_val = lst[i+1]

        if is_first_object and not is_last_object:
            found += 1 if current_value > next_val else 0
        elif is_last_object and not is_first_object:
            found += 1 if current_value > previous_val else 0
        elif not is_last_object and not is_last_object:
            found += 1 if previous_val < current_value > next_val else 0

    return found


print(peaks([1, 2, 3]))

另一种方式。

检查极端然后检查核心,三个三个:

def count_peaks(ls):
    res = [ls[0] > ls[1], ls[-1] > ls[-2]]
    for n in range(len(ls)-2):
        a, b, c = ls[n:n+3]
        res.insert(-1, b > max([a, c]))
    return res

在最后一个元素之前插入,以反映结果中的峰位置。

因此,在 [1,2,1,2,4,5] 的情况下:

count_peaks([1,2,1,2,4,5])
#=>[False, True, False, False, False, True]

只需 return sum(res) 即可获得所需结果:2

你可以在前面和最后添加第一个元素和倒数第二个元素的代理值,然后检查从第一个元素到倒数第二个元素的条件

def peaks(array):
        if len(array)<2:
            return 0
        array2 = [array[1]] + array + [array[-2]]
        
        count = sum([1 for i in range(len(array2)-2) if  array2[i+2]<array2[i+1] >array2[i]])
        return count

试试这个

def peaks(lst):
    num = 0
    leni = len(lst)
    
    for i in range(leni):
        if i == 0:
            if lst[i] > lst[i+1]:
                num = num + 1
        elif i == leni-1:
            if lst[i] > lst[i-1]:
                num = num + 1
        else:
            if lst[i] > lst[i-1] and lst[i] > lst[i+1]:
                num = num + 1
    return num

直接相邻峰的计数可能是一项与性能相关的任务,实现列表越来越长。比较 运行 时间的充分理由。在第一个 运行 中,我决定只使用一个测试集。显然,不同的实现可能会在不同长度的列表中显示出它们的优势。例如,边界值处理的最佳实现似乎是一个取决于列表长度的候选者。

输出:

count_peaks_schwobaseggl: elapsed time 1.44 s
count_peaks_sahasrara62: elapsed time 1.50 s
count_peaks_saikat: elapsed time 2.27 s
count_peaks_tom_wojcik: elapsed time 4.11 s
count_peaks_igian: elapsed time 3.65 s
count_peaks_cloud_balancing: elapsed time 1.86 s

实施:

import random
import time
from typing import List


def measure_runtime_in_s(func, test_lists):
    start = time.time()
    results = []
    for test_list in test_lists:
        max_cnt = func(test_list)
        results.append(max_cnt)
    return time.time() - start, results


def run_experiment(funcs, nlists=1000, len_range=(20, 10000), num_range=(-100, 100)):
    assert len(funcs) > 0
    # generate test data
    test_lists = [[random.randint(*num_range) for _ in range(random.randint(*len_range))]
                  for _ in range(nlists)]

    # run it for all implementations and check results
    _, ref_results = measure_runtime_in_s(funcs[0], test_lists)
    for func in funcs:
        failed = False
        time_in_s, results = measure_runtime_in_s(func, test_lists)
        if not all(result == ref_result for result, ref_result in zip(results, ref_results)):
            failed = True
        print(
            f"{func.__name__}: elapsed time {time_in_s:.2f} s"
            + (" (FAILED TESTS!)" if failed else ""))


def count_peaks_schwobaseggl(lst):
    lst = [float("-inf")] + lst + [float("-inf")]
    return sum(a < b > c for a, b, c in zip(lst, lst[1:], lst[2:]))


def count_peaks_sahasrara62(array):
    if len(array) < 2:
        return 0
    array2 = [array[1]] + array + [array[-2]]

    count = sum([1 for i in range(len(array2) - 2) if array2[i + 2] < array2[i + 1] > array2[i]])
    return count


def count_peaks_saikat(lst):
    num = 0
    leni = len(lst)

    for i in range(leni):
        if i == 0:
            if lst[i] > lst[i + 1]:
                num = num + 1
        elif i == leni - 1:
            if lst[i] > lst[i - 1]:
                num = num + 1
        else:
            if lst[i] > lst[i - 1] and lst[i] > lst[i + 1]:
                num = num + 1
    return num


def count_peaks_igian(ls):
    res = [ls[0] > ls[1], ls[-1] > ls[-2]]
    for n in range(len(ls)-2):
        a, b, c = ls[n:n+3]
        res.insert(-1, b > max([a, c]))
    return sum(res)  # < modified


def count_peaks_tom_wojcik(lst: List[int]):
    found = 0

    for i, current_value in enumerate(lst):
        is_first_object = i == 0
        is_last_object = i == len(lst) - 1

        if is_first_object:
            previous_val = None
        else:
            previous_val = lst[i-1]

        if is_last_object:
            next_val = None
        else:
            next_val = lst[i+1]

        if is_first_object and not is_last_object:
            found += 1 if current_value > next_val else 0
        elif is_last_object and not is_first_object:
            found += 1 if current_value > previous_val else 0
        elif not is_last_object and not is_last_object:
            found += 1 if previous_val < current_value > next_val else 0

    return found


def count_peaks_cloud_balancing(lst):
    lst_len = len(lst)
    hits = 0

    for i in range(1, lst_len - 1):
        num_to_test = lst[i]
        before = lst[i - 1]
        after = lst[i + 1]
        if num_to_test > before and num_to_test > after:
            hits += 1
    # This is for the case lst contains only 1 member and you want to count it as 1
    if lst_len == 1:
        hits += 1
    # For checking the edges
    if lst_len > 1:
        if lst[0] > lst[1]:
            hits += 1
        if lst[lst_len - 1] > lst[lst_len - 2]:
            hits += 1

    return hits


if __name__ == "__main__":
    run_experiment([
        count_peaks_schwobaseggl,
        count_peaks_sahasrara62,
        count_peaks_saikat,
        count_peaks_tom_wojcik,
        count_peaks_igian,
        count_peaks_cloud_balancing,
    ])