有没有更好的方法在python中编写以下方法?

时间:2015-04-27 00:19:08

标签: python python-2.7

我正在编写一个小程序,在python中,它将从算术级数中找到一个单独的缺失元素(其中起始元素可以是正数和负数,系列可以是升序或降序)。

所以例如:如果输入是1 3 5 9 11,那么函数应该返回7,因为这是上面AP系列中唯一缺失的元素。 输入格式:输入元素由1个空格分隔,而不是通常所做的逗号。

以下是代码:

def find_missing_elm_ap_series(n, series):
    ap = series
    ap = ap.split(' ')
    ap = [int(i) for i in ap]
    cd = []
    for i in range(n-1):
        cd.append(ap[i+1]-ap[i])
    common_diff = 0

    if len(set(cd)) == 1:
        print 'The series is complete'
        return series
    else:
        cd = [abs(i) for i in cd]
        common_diff = min(cd)
        if ap[0] > ap[1]:
            common_diff = (-1)*common_diff


    new_ap = []
    for i in range(n+1):
        new_ap.append(ap[0] + i*common_diff)

    missing_element = set(new_ap).difference(set(ap)) 
    return missing_element

其中n是所提供系列的长度(缺少元素的系列:上例中为5)。

我确信在python中还有其他更简洁,更优雅的编写代码的方法。有人可以帮忙吗? 谢谢 顺便说一句:我自己学习python,因此也是问题。

6 个答案:

答案 0 :(得分:3)

基于以下事实:如果缺少一个元素,那么它就是expected-sum(series) - actual-sum(series)。从n开始到a开始的b元素系列的预期总和为(a+b)*n/2。剩下的就是Python:

def find_missing(series):
    A = map(int, series.split(' '))
    a, b, n, sumA = A[0], A[-1], len(A), sum(A)

    if (a+b)*n/2 == sumA:
        return None #no element missing

    return (a+b)*(n+1)/2-sumA

print find_missing("1 3 5 9")    #7
print find_missing("-1 1 3 5 9") #7
print find_missing("9 6 0")      #3
print find_missing("1 2 3")      #None
print find_missing("-3 1 3 5")   #-1

答案 1 :(得分:2)

嗯......你可以做得更简单,但它会彻底改变你的算法。

首先,你可以证明算术级数的步骤是ap[1] - ap[0],除非ap[2] - ap[1]的幅度低于它,在这种情况下,缺失的元素在0和1之间。是的,因为只有一个缺失的元素。)

然后你可以拿ap[0] + n * step打印第一个不匹配的。

这是源代码(也实现了一些小的快捷方式,例如将前三行分组为一个):

def find_missing_elm_ap_series(n, series):
    ap = [int(i) for i in series.split(' ')]
    step = ap[1] - ap[0]
    if (abs(ap[2] - ap[1]) <= abs(step)): # Check missing elt is not between 0 and 1
        return ap[0] + ap[2] - ap[1]
    for (i, val) in zip(range(len(ap)), ap): # And check position of missing element
        if ap[0] + i * step != val:
            return ap[0] + i * step
    return series # missing element not found

答案 2 :(得分:1)

代码似乎正在运行。可能有一种稍微简单的方法来完成它。这是因为您不必尝试查看所有值以获得常见差异。以下代码仅查看第1个和第2个以及最后一个和第二个之间的差异。

这适用于只丢失一个值的事件(并且列表的长度至少为3)。由于值之间的最小差异将为您提供共同的差异。

def find_missing(prog):
    # First we cast them to numbers.
    items = [int(x) for x in prog.split()]

    #Then we compare the first and second
    first_to_second =  items[1] - items[0]

    #then we compare the last to second last
    last_to_second_last = items[-1] - items[-2]

    #Now we have to care about which one is closes
    # to zero
    if abs(first_to_second) < abs(last_to_second_last):
        change = first_to_second
    else:
        change = last_to_second_last


    #Iterate through the list. As soon as we find a gap
    #that is larger than change, we fill in and return

    for i in range(1, len(items)):
        comp = items[i] - items[i-1]

        if comp != change:
            return items[i-1] + change

    #There was no gap
    return None

print(find_missing("1 3 5 9"))    #7
print(find_missing("-1 1 3 5 9")) #7
print(find_missing("9 6 0"))      #3
print(find_missing("1 2 3"))      #None

前面的代码显示了这个例子。首先尝试在列表的每个值之间找到变化。然后迭代直到错过更改,并返回预期的值。

答案 3 :(得分:0)

这就是我想到的方式:找到数组元素之间最大差异的位置;然后从其他差异(差异列表中的所有相同和最小数字)重新生成序列中的预期数字:

def find_missing(a):
    d = [a[i+1] - a[i] for i in range(len(a)-1)]
    i = d.index(max(d))
    x = min(d)
    return a[0] + (i+1)*x

print find_missing([1,3,5,9,11])
7
print find_missing([1,5,7,9,11])
3

答案 4 :(得分:0)

假设第一个&amp;最后的项目不会丢失,我们也可以使用range()xrange()与常见差异的步骤,完全摆脱n,它也可以返回超过1个缺失项目(虽然不可靠取决于缺少的项目数量):

In [13]: def find_missing_elm(series):
             ap = map(int, series.split())
             cd = map(lambda x: x[1]-x[0], zip(ap[:-1], ap[1:]))
             if len(set(cd)) == 1:
                 print 'complete series'
                 return ap
             mcd = min(cd) if ap[0] < ap[1] else max(cd)
             sap = set(ap)
             return filter(lambda x: x not in sap, xrange(ap[0], ap[-1], mcd))
   ....:

In [14]: find_missing_elm('1 3 5 9 11 15')
Out[14]: [7, 13]

In [15]: find_missing_elm('15 11 9 5 3 1')
Out[15]: [13, 7]

答案 5 :(得分:0)

以下是一些想法:

  • 传递系列的长度似乎是一个坏主意。该功能可以更容易地计算长度
  • 没有理由将系列分配给ap,只使用系列执行功能并将结果分配给ap
  • 分割字符串时,不要给出sep参数。如果不给出参数,则也将删除连续的空格,并且也将忽略前导和尾随空格。这对数据格式更友好。
  • 我结合了一些操作。例如,拆分和转换为整数的列表推导有意义地组合在一起。也不需要将cd创建为列表,然后将其转换为集合。只需将其构建为一组开始。
  • 我不喜欢该函数在没有缺少元素的情况下返回原始系列。值None将更符合函数的名称。
  • 您的原始函数返回了一个设置为结果的项目。这看起来很奇怪,所以我使用pop()来提取该项并返回缺少的元素。
  • 最后一项更多的是将底部的所有代码合并到一个语句中的实验。不知道它是否更好,但这是值得思考的问题。我建立了一个包含所有正确数字的集合和一个具有给定数字的集合,然后减去它们并返回丢失的数字。

以下是我提出的代码:

def find_missing_elm_ap_series(series):
    ap = [int(i) for i in series.split()]
    n = len(ap)
    cd = {ap[i+1]-ap[i] for i in range(n-1)}

    if len(cd) == 1:
        print 'The series is complete'
        return None
    else:
        common_diff = min([abs(i) for i in cd])
        if ap[0] > ap[1]:
            common_diff = (-1)*common_diff

    return set(range(ap[0],ap[0]+common_diff*n,common_diff)).difference(set(ap)).pop()