【问题标题】:Remove an even/odd number from an odd/even Python list从奇数/偶数 Python 列表中删除偶数/奇数
【发布时间】:2017-02-06 14:37:05
【问题描述】:

我正在尝试更好地理解 Python 中的列表理解。我用一个相当不雅的解决方案完成了关于代码战的在线挑战,如下所示。

挑战是:

  1. 给定一个偶数列表和一个奇数,返回奇数
  2. 给定一个奇数列表和一个偶数,返回偶数

我的(不优雅的)解决方案是:

def find_outlier(integers):
    o = []
    e = []
    for i in integers:
        if i % 2 == 0:
            e.append(i)
        else:
            o.append(i)
    # use sums to return int type
    if len(o) == 1:
        return sum(o)
    else:
        return sum(e)

效果很好,但似乎很暴力。我认为使用 oe 之类的占位符列表启动(大多数)函数非常“像菜鸟”,我错了吗?

我很想更好地理解为什么这个解决方案适用于奇数列表,但在偶数列表上失败,以便更好地理解列表理解:

def find_outlier(integers):
    if [x for x in integers if x % 2 == 0]:
       return [x for x in integers if x % 2 == 0]
    elif [x for x in integers if x % 2 != 0]:
       return [x for x in integers if x % 2 != 0]
    else:
        print "wtf!"

o = [1,3,4,5]
e = [2,4,6,7]

In[1]: find_outlier(o)
Out[1]: [4]

In[2]: find_outlier(e)
Out[2]: [2, 4, 6]

Out[2] 应该返回 7

提前感谢您提供任何见解。

【问题讨论】:

  • 列表推导不是最好的解决方案,不是。尝试通过检查最少数量的元素来解决它(前 2 个元素,如果它们的类型不同,则获得第 3 个以打破平局,否则迭代直到找到不适合尾部的元素)。跨度>
  • @D8Amonk 这就是那种引入错误的假设。当然:您假设,但是如果您在编写列表时在某些时候将17817 错误输入,您很容易在不知情的情况下结束,在这种情况下,如果您不这样做不要检查你会得到错误的结果。安全总比抱歉并引发异常好,尤其是在这种情况下,检查该条件是计算的一部分,因此您基本上没有性能损失。
  • @D8Amonk:随时欢迎您进行自我回答 :-) 不过,请务必涵盖“我的功能为什么失败”的情况;你正在为有同样问题的人写这篇文章。
  • @Bakuriu:因为这是一个编码挑战,我认为代码可以假设只有一个异常值。
  • @MartijnPieters 然而,问题和答案应该不仅对 OP 有用。其他人可能必须在现实生活中解决同样的问题,在这种情况下,更好的解决方案也是处理错误情况的解决方案。

标签: python list list-comprehension


【解决方案1】:

您的尝试失败了,因为第一个 if总是正确的。您将始终拥有一个至少包含 1 个元素的列表;要么是奇数,要么是奇数,并且您测试了一个包含所有偶数的列表,否则您有一个包含 one 偶数的列表。只有 empty 列表是错误的。

列表推导不是最好的解决方案,不是。尝试通过检查最少数量的元素来解决它(前 2 个元素,如果它们的类型不同,则获得第 3 个以打破平局,否则迭代直到找到不适合尾部的元素):

def find_outlier(iterable):
    it = iter(iterable)
    first = next(it)
    second = next(it)
    parity = first % 2
    if second % 2 != parity:
        # odd one out is first or second, 3rd will tell which
        return first if next(it) % 2 != parity else second
    else:
        # the odd one out is later on; iterate until we find the exception
        return next(i for i in it if i % 2 != parity)

如果输入可迭代的元素少于 3 个,或者没有找到异常,则上面将抛出 StopIteration 异常。它也不会处理有多个异常的情况(例如 2 偶数后跟 2 奇数;在这种情况下将返回第一个奇数值)。

【讨论】:

【解决方案2】:

最有效的答案会变得有点难看。

def f(in_list):
    g = (i for i in in_list)
    first = next(g)
    second = next(g) #The problem as described doesn't make sense for fewer than 3 elements.  Let them handle the exceptions.
    if first%2 == second%2:
        a = first%2
        for el in g:
            if el%2 != a:
                return el
    else:
        third = next(g)
        if third%2 == first%2:
            return second
        else:
            return first
    except ValueError('Got a bad list, all evens or all odds')

【讨论】:

  • (i for i in in_list) 最好写成iter(in_list),这里不需要使用生成器表达式。您可以存储奇偶校验(a 在您的代码中)并将其用于两个分支。
【解决方案3】:

这个响应有什么缺点(位于this particular challenge 的解决方案堆栈的顶部)?

def find_outlier(int):
    odds = [x for x in int if x%2!=0]
    evens= [x for x in int if x%2==0]
    return odds[0] if len(odds)<len(evens) else evens[0]

【讨论】:

  • @MartijnPieters 这是投票最多的解决方案。当我写我的时候我没有看到它,但这让我更加困惑为什么我的不起作用,因为它似乎使用了我尝试的相同的列表组合逻辑......
  • 这会将列表分成两部分,并使用len() 比较哪个更短。您的代码假定其中之一将是,这是一个错误的假设。
  • 请注意,这必须处理输入列表中的所有值。两次。我只需要处理列表,直到发现异常。这可能与前 3 个元素一样少。用[1, 3, 4] + list(range(5, 1000000, 2))试试这个。
  • 我注意到这可能在 codewars 中获得最高投票,但 cmets 表明这确实不应该在顶部。鉴于输入可能很大的描述,这确实很昂贵。
  • @MartijnPieters 我开始理解使用您的迭代器的原因......尽管如此......仍然吸收关于 OP cmets 的辩论......
猜你喜欢
  • 1970-01-01
  • 2022-12-17
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2016-04-21
  • 1970-01-01
  • 2020-10-28
  • 1970-01-01
相关资源
最近更新 更多