列表上的排列 nPr(5,3) 数量错误

发布于 2025-01-12 03:23:21 字数 784 浏览 0 评论 0原文

该程序的目标是对 x 进行尽可能多的排列,大小为 3 (nPr(5,3),因此迭代 <代码>(i,j,k))。

我尝试实现排列 nPr(5,3),其中 5 是列表 x3 的长度 是元组 (i,j,k) 的长度:

# x will never have any repeats
x = [1, 2, 3, 4, 5]
# nPr(5,3) = 60
y = []


for i in x:
    for j in x:
        for k in x:
            y.append((i, j, k))

print(f"Len of y = {len(y)}")

我期望 len(y) 为 60,如 nPr( 5,3) = 60。但我得到输出Len of y = 125。另外,使用 y = set() 并不能解决这个问题

  • 我做错了什么?
  • 如何修复此代码以使其工作(不使用 itertools

答案 TL;DR:我允许重复 (1,1 ,1)

The goal of this program is to make as many permutations of x in size 3 (nPr(5,3), hence the iterations of (i, j, k)).

My effort on trying to achieve the permutations nPr(5,3), where 5 is the length of the list x and 3 is the length of the tuple (i,j,k):

# x will never have any repeats
x = [1, 2, 3, 4, 5]
# nPr(5,3) = 60
y = []


for i in x:
    for j in x:
        for k in x:
            y.append((i, j, k))

print(f"Len of y = {len(y)}")

I'm expecting len(y) to be 60, as nPr(5,3) = 60. But i get the output Len of y = 125. Also, making y = set() does not fix this issue

  • What have I done wrong?
  • How do I fix this code to work (without using itertools)

Answer TL;DR: I was allowing duplicates (1,1,1)

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

要走就滚别墨迹 2025-01-19 03:23:22

您允许重复(例如,[1,1,1] 和 [2,2,2])。值 60 用于无重复的排列。您可以通过检查是否没有重复某个值来做到这一点。

注意,此代码仅在 x 中没有重复的情况下才有效。如果存在重复项,则必须改用索引(即 for i in range(len(x)):)。

x = [1,2,3,4,5]
y = []
for i in x:
    for j in x:
        if i == j:
            continue
        for k in x:
            if i!=k and j!= k: 
                y.append((i,j,k))
print(y)

You are allowing repeats (for example, [1,1,1] and [2,2,2]). The value of 60 is for permutations without repeats. You do that by checking that you aren't repeating a value.

NOTE that this code only works if there are no repeats in x. If there are duplicates, then you would have to use indexes instead (that is, for i in range(len(x)):).

x = [1,2,3,4,5]
y = []
for i in x:
    for j in x:
        if i == j:
            continue
        for k in x:
            if i!=k and j!= k: 
                y.append((i,j,k))
print(y)
街角迷惘 2025-01-19 03:23:22

正如 Tim Roberts 所指出的,我添加了 i,j 或 k(1,1,1) 的重复。我的解决方法是确保 i,j 和 k 不同:

for i in x:
    for j in x:
        for k in x:
            # If i,j,k are different
            if len(set((i, j, k))) == 3:
                y.append((i, j, k))

因为 set((i, j, k)) 将删除元组中的重复项 (i, j, k),因此长度必须等于 3。如果我需要将 nPr(n,r) 递归为 set( (i,j,k...r)) == r

As pointed out by Tim Roberts, I was adding repeats of i,j or k, (1,1,1). My fix is to just make sure i,j and k are different:

for i in x:
    for j in x:
        for k in x:
            # If i,j,k are different
            if len(set((i, j, k))) == 3:
                y.append((i, j, k))

As set((i, j, k)) will remove the duplicates in the tuple (i, j, k), so the length must equal 3. This is also helpful if I need to make this recursive for nPr(n,r) as set((i, j, k ... r)) == r.

吾性傲以野 2025-01-19 03:23:22

这会起作用,尽管它对我来说嵌套得有点太深了:

y = []
for i in x:
    for j in x:
        if i != j:
            for k in x:
                if i != k and j != k:
                    y.append((i, j, k))

assert list(itertools.permutations(x, 3)) == y

否定条件并使用 continue 会增加可读性:

y = []
for i in x:
    for j in x:
        if i == j:
            continue
        for k in x:
            if i == k or j == k:
                continue
            y.append((i, j, k))

assert list(itertools.permutations(x, 3)) == y

但这只有在 x 的所有成员都是唯一的情况下才有效。更好的方法是检查索引是否不同:

y = []
for i in range(len(x)):
    for j in range(len(x)):
        if i == j:
            continue
        for k in range(len(x)):
            if i == k or j == k:
                continue
            y.append((x[i], x[j], x[k]))

assert list(itertools.permutations(x, 3)) == y

我们还可以通过递归来完成这项工作,在过程中参数化 r (每个排列中的项目数),尽管没有 动态编程,这种方法将为大型 x 做很多额外的工作,并且r

# if x were hashable, i.e. a tuple in this case, we could use the
# @functools.cache decorator to avoid repeated work
def permutations(x, r):
    if not r:
        return [(),]
    res = []
    for i in range(len(x)):
        perms_without_x_i = permutations(x[:i] + x[i + 1 :], r - 1)
        res += [(x[i],) + p for p in perms_without_x_i]
    return res


assert permutations(x, 3) == list(itertools.permutations(x, 3))

但最好的方法可能是直接从 文档

def permutations(iterable, r=None):
    # permutations('ABCD', 2) --> AB AC AD BA BC BD CA CB CD DA DB DC
    # permutations(range(3)) --> 012 021 102 120 201 210
    pool = tuple(iterable)
    n = len(pool)
    r = n if r is None else r
    if r > n:
        return
    indices = list(range(n))
    cycles = list(range(n, n-r, -1))
    yield tuple(pool[i] for i in indices[:r])
    while n:
        for i in reversed(range(r)):
            cycles[i] -= 1
            if cycles[i] == 0:
                indices[i:] = indices[i+1:] + indices[i:i+1]
                cycles[i] = n - i
            else:
                j = cycles[i]
                indices[i], indices[-j] = indices[-j], indices[i]
                yield tuple(pool[i] for i in indices[:r])
                break
        else:
            return

This will work, though it's a bit too deeply nested for my taste:

y = []
for i in x:
    for j in x:
        if i != j:
            for k in x:
                if i != k and j != k:
                    y.append((i, j, k))

assert list(itertools.permutations(x, 3)) == y

Negating the conditions and using continue increases readability:

y = []
for i in x:
    for j in x:
        if i == j:
            continue
        for k in x:
            if i == k or j == k:
                continue
            y.append((i, j, k))

assert list(itertools.permutations(x, 3)) == y

But this will only work if all members of x are unique. Better would be to check that the indices are different:

y = []
for i in range(len(x)):
    for j in range(len(x)):
        if i == j:
            continue
        for k in range(len(x)):
            if i == k or j == k:
                continue
            y.append((x[i], x[j], x[k]))

assert list(itertools.permutations(x, 3)) == y

We could also do the job with recursion, parameterizing r (number of items in each permutation) in the process, though without dynamic programming, this approach will do a lot of extra work for large x and r:

# if x were hashable, i.e. a tuple in this case, we could use the
# @functools.cache decorator to avoid repeated work
def permutations(x, r):
    if not r:
        return [(),]
    res = []
    for i in range(len(x)):
        perms_without_x_i = permutations(x[:i] + x[i + 1 :], r - 1)
        res += [(x[i],) + p for p in perms_without_x_i]
    return res


assert permutations(x, 3) == list(itertools.permutations(x, 3))

But probably the best way of all is to steal the answer directly from the docs:

def permutations(iterable, r=None):
    # permutations('ABCD', 2) --> AB AC AD BA BC BD CA CB CD DA DB DC
    # permutations(range(3)) --> 012 021 102 120 201 210
    pool = tuple(iterable)
    n = len(pool)
    r = n if r is None else r
    if r > n:
        return
    indices = list(range(n))
    cycles = list(range(n, n-r, -1))
    yield tuple(pool[i] for i in indices[:r])
    while n:
        for i in reversed(range(r)):
            cycles[i] -= 1
            if cycles[i] == 0:
                indices[i:] = indices[i+1:] + indices[i:i+1]
                cycles[i] = n - i
            else:
                j = cycles[i]
                indices[i], indices[-j] = indices[-j], indices[i]
                yield tuple(pool[i] for i in indices[:r])
                break
        else:
            return
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文