根据端点递归划分列表

时间:2019-06-26 15:23:05

标签: python arrays list function recursion

这就是我想要做的。 拿清单:

list1 = [0,2]

此列表的起点为0,终点为2。 现在,如果我们使用此列表的中点,该列表将变为:

list1 = [0,1,2]

现在,如果我们再次递归拆分列表(取中点的中点),则列表将变为:

list1 = [0,.5,1,1.5,2]

我需要一个函数来生成这样的列表,最好通过跟踪变量来生成。因此,举例来说,假设有一个变量n跟踪某事。当n = 1时,列表可能是[0,1,2],而当n = 2时,列表可能是[0,.5,1,1.5,2],我将增加值以保持跟踪我对列表进行了划分的次数。

我知道您需要为此使用递归,但是我不确定如何实现它。

应该是这样的:

def recursive(list1,a,b,n):
  """list 1 is a list of values, a and b are the start
     and end points of the list, and n is an int representing
     how many times the list needs to be divided"""
   int mid = len(list1)//2
 stuff

有人可以帮我编写此功能吗?不用于家庭作业,这是我正在从事的项目的一部分,其中涉及使用网格分析将矩形分成多个部分。

这是我到目前为止所拥有的:

def recursive(a,b,list1,n):
  w = b - a
  mid = a +  w / 2
  left = list1[0:mid]
  right = list1[mid:len(list1)-1]
  return recursive(a,mid,list1,n) + mid + recursive(mid,b,list1,n)

但是我不确定如何将n合并到这里。

注意:list1最初是[a,b]-我只是手动输入一个,但是我敢肯定有更好的方法。

5 个答案:

答案 0 :(得分:1)

您可以使用一些算术和切片来确定结果的大小,并用值有效地填充它。

虽然不是必需的,但您可以通过将此功能包装在一个简单的辅助函数中来实现递归调用,该函数将检查您正在进行的拆分迭代,并在不超出限制的情况下进一步拆分列表。


def expand(a):
    """
    expands a list based on average values between every two values
    """
    o = [0] * ((len(a) * 2) - 1)
    o[::2] = a
    o[1::2] = [(x+y)/2 for x, y in zip(a, a[1:])]
    return o

def rec_expand(a, n):
    if n == 0:
        return a
    else:
        return rec_expand(expand(a), n-1)

实际

>>> rec_expand([0, 2], 2)
[0, 0.5, 1.0, 1.5, 2]

>>> rec_expand([0, 2], 4)
[0,
 0.125,
 0.25,
 0.375,
 0.5,
 0.625,
 0.75,
 0.875,
 1.0,
 1.125,
 1.25,
 1.375,
 1.5,
 1.625,
 1.75,
 1.875,
 2]

答案 1 :(得分:1)

您已经生成了一些有趣的答案。这里还有两个。

我的第一个使用迭代器来避免 对列表进行切片,并且是递归的,因为这似乎是最自然的公式。

def list_split(orig, n):
    if not n:
        return orig
    else:
        li = iter(orig)
        this = next(li)
        result = [this]
        for nxt in li:
            result.extend([(this+nxt)/2, nxt])
            this = nxt
        return list_split(result, n-1)

for i in range(6):
    print(i, list_split([0, 2], i))

此打印

0 [0, 2]
1 [0, 1.0, 2]
2 [0, 0.5, 1.0, 1.5, 2]
3 [0, 0.25, 0.5, 0.75, 1.0, 1.25, 1.5, 1.75, 2]
4 [0, 0.125, 0.25, 0.375, 0.5, 0.625, 0.75, 0.875, 1.0, 1.125, 1.25, 1.375, 1.5, 1.625, 1.75, 1.875, 2]
5 [0, 0.0625, 0.125, 0.1875, 0.25, 0.3125, 0.375, 0.4375, 0.5, 0.5625, 0.625, 0.6875, 0.75, 0.8125, 0.875, 0.9375, 1.0, 1.0625, 1.125, 1.1875, 1.25, 1.3125, 1.375, 1.4375, 1.5, 1.5625, 1.625, 1.6875, 1.75, 1.8125, 1.875, 1.9375, 2]

我的第二个观点是基于这样的观察:如果始终从两个元素开始,则不必进行递归。假设这些元素是mnmx。在N应用拆分操作之后,您将在其中包含2^N+1个元素,因此元素之间的数字距离将为(mx-mn)/(2**N)

鉴于此信息,因此应该可以确定性地计算数组的元素,甚至更容易use numpy.linspace像这样:

def grid(emin, emax, N):
    return numpy.linspace(emin, emax, 2**N+1)

这似乎给出了相同的答案,并且从长远来看可能会为您提供最好的服务。

答案 2 :(得分:0)

您可以使用for循环

import numpy as np

def add_midpoints(orig_list, n):
    for i in range(n):
        new_list = []
        for j in range(len(orig_list)-1):
            new_list.append(np.mean(orig_list[j:(j+2)]))

        orig_list = orig_list + new_list
        orig_list.sort()

    return orig_list

add_midpoints([0,2],1)
[0, 1.0, 2]
add_midpoints([0,2],2)
[0, 0.5, 1.0, 1.5, 2]
add_midpoints([0,2],3)
[0, 0.25, 0.5, 0.75, 1.0, 1.25, 1.5, 1.75, 2]

答案 3 :(得分:0)

您还可以完全非递归且无循环地执行此操作。我们在这里所做的只是像大多数帝国制标尺一样,在两个数字之间建立一个二进制标度。

def binary_scale(start, stop, level):
    length = stop - start
    scale = 2 ** level
    return [start + i * length / scale for i in range(scale + 1)]

使用中:

>>> binary_scale(0, 10, 0)
[0.0, 10.0]
>>> binary_scale(0, 10, 2)
[0.0, 2.5, 5.0, 7.5, 10.0]
>>> binary_scale(10, 0, 1)
[10.0, 5.0, 0.0]

答案 4 :(得分:0)

有趣的反模式:

def expand(a, n):
    for _ in range(n):

        a[:-1] = sum(([a[i], (a[i] + a[i + 1]) / 2] for i in range(len(a) - 1)), [])

    return a

print(expand([0, 2], 2))

输出

% python3 test.py
[0, 0.5, 1.0, 1.5, 2]
%