如何获得一个单元格中的排列列表?

问题描述 投票:0回答:4

下面是 5 列 - 第 6 列包含所需的结果:5 列中的名称在每个可能的排列中。

两行只有两列有值 - 所以第 6 列中只有两个排列(由“;”分隔)。

一行有 4 个值,所以有 24 个排列。

对不起图片,我无法弄清楚如何将表格从 Excel 粘贴到 Stack 而不必重写它。

真实数据集中的行可以有 1 个值、5 个值或介于两者之间的任何值。

这里的答案似乎只适用于二维数组——这个数组是一维的。我想不出任何明显的方法来使其成为 2d 以便这些解决方案起作用,这似乎也不是一种有效的方法。上述答案中的一个公式如下(我查看了所有这些公式,但不知道如何根据我的需要调整它们):

=LET(A,A1:C3,B,ROWS(A),C,COLUMNS(A),D,B^C,E,UNIQUE(MAKEARRAY(D,C,LAMBDA(rw,cl,INDEX(IF(A="","",A),MOD(CEILING(rw/(D/(B^cl)),1)-1,B)+1,cl)))),FILTER(E,MMULT(--(E<>""),SEQUENCE(C,,,0))=C))
我用谷歌搜索过的大多数解决方案在 1 行 5 列的简单数组上似乎也不起作用(或者我无法使它们起作用)。

我试着从头开始做,并且生成了一个仅包含数字 1-5 且没有重复的数字列表 -

=LET(firstperm,VALUE(CONCAT(SEQUENCE(1,COLUMNS(Tablestu[@[First Name]:[Preferred Last Name]])))),lastperm,VALUE(CONCAT(SORT(SEQUENCE(1,COLUMNS(Tablestu[@[First Name]:[Preferred Last Name]])),,-1,TRUE))),diff,(lastperm-firstperm)+1,list,SEQUENCE(diff,1,firstperm),wanted,(IF((ISNUMBER(SEARCH("1",list))*ISNUMBER(SEARCH("2",list))*ISNUMBER(SEARCH("3",list))*ISNUMBER(SEARCH("4",list))*ISNUMBER(SEARCH("5",list))),list,"")),FILTER(wanted,wanted<>"",""))
我想我可以以某种方式拆分这 5 位数字,并使用 INDEX 公式按该顺序返回单词。 IE。 31452 会返回第三个单词,然后是第一个,然后是第四个,依此类推......但我仍然需要一百万次键盘敲击才能将它变成我需要的东西,而且它会非常低效我什至到了那里。

链接的答案似乎是正确的 - 我正在使用 Excel 365,我需要一个使用公式的解决方案,而不是 VBA 或 power query。

LAMDA 和 LET 都很好。

arrays excel excel-formula permutation
4个回答
3
投票

警告:不建议将其作为通用解决方案,但由于 OP 给出的条目数上限为 5,因此可能值得考虑。

=LET( ζ,A2:E2, ξ,COUNTA(ζ), κ,SEQUENCE(,ξ), λ,LEFT(12345,ξ), γ,REPT(1+ξ,ξ)-λ, δ,SEQUENCE(γ-λ+1,,λ), α,INDEX(FILTER(ζ,ζ<>""), MID(FILTER(δ,MMULT(N(ISERR(FIND(MID(λ,κ,1),δ))),TOCOL(κ))=0),κ,1) ), TEXTJOIN(";",,BYROW(α,LAMBDA(β,CONCAT(β)))) )
    

3
投票
备选方案:

=LET(range, A1:E1, f, FILTER(range,range<>""), c, COLUMNS(f), s, c^c, a, MAKEARRAY( s, c, LAMBDA( rw, cl, MOD(CEILING(rw/(s/(c^cl)),1)-1,c)+1)), p, FILTER(a, BYROW( a, LAMBDA( x, AND(MMULT(N(TRANSPOSE(x)=x),SEQUENCE(c)^0)=1)))), TEXTJOIN(";",,UNIQUE(BYROW(p,LAMBDA(x,TEXTJOIN("",1,CHOOSECOLS(f,x)))))))
这也考虑到如果在范围内使用重复的名称,它不会产生重复的排列。


0
投票
我将此添加为替代方法,因为该方法与我之前的回答中使用的方法有很大不同。

=LET( ζ,A2:E2, ξ,FILTER(ζ,ζ<>""), TEXTJOIN(";",, SORT(UNIQUE(BYROW(RANDARRAY(2^10,COLUMNS(ξ)),LAMBDA(γ,CONCAT(SORTBY(ξ,γ)))))) ) )
只要

RANDARRAY

的第一个参数选择得足够大,结果数组不唯一的概率就会小到几乎可以保证正确的输出。在这里,
2^10
 似乎足以容纳最多 5 个非空白条目。

同样,此设置不容易扩展到超过 5 个非空白条目,但由于其简洁性和/或性能可能值得考虑。


0
投票
考虑到之前答案中的评论,关于 Excel 性能以及 Excel 不提供开箱即用的置换器生成器这一事实。该解决方案使用一种有效的方法,通过免费的插件使用 Excel javascript 集成:

Script Lab,它是一个 Microsoft Garage Project 和它的多平台我用 Excel 版本测试过,但您可以尝试使用 Excel Desktop。

关于用于排列的 javascript 算法,我从问题中改编了其中两个:

JavaScript 中的排列?.

改编我的意思是:

    添加参数定义所需的注释。查看
  • Office 脚本元数据参考 了解更多信息。
  • 将输入数组 (
  • arr
    ) 从二维数组转换为一维数组。 javascript 问题中的所有算法都采用一维数组,但是当我们调用接收 Excel 范围的 javascript 函数时,该范围表示为二维数组 (
    [][]
    ),因此我们使用内置数组 
    flat()
     在调用算法之前进行转换的方法。
来自@caub:最短的一个,但效率不高

/** * Generates all permutation without repetition of the input argument * @customfunction * @param {any[][]} arr Array of input values * @returns {any[][]} 2D array with all permutations. */ function permute(arr) { if (Array.isArray(arr[0])) { arr = arr.flat(); } function recur(a) { if (!a.length) return [[]]; return a.flatMap((x, i) => { return recur(a.filter((v, j) => i !== j)).map((vs) => [x, ...vs]); }); } return recur(arr); }
来自@le_m:更大,但最有效的

/** * Generates all permutation without repeatiton of the input argument * @customfunction * @param {any[][]} arr Array of input values * @returns {any[][]} 2D array with all permutations. */ function permute_eff(arr) { if (Array.isArray(arr[0])) { arr = arr.flat(); } var length = arr.length, result = [arr.slice()], c = new Array(length).fill(0), i = 1, k, p; while (i < length) { if (c[i] < i) { k = i % 2 && c[i]; p = arr[i]; arr[i] = arr[k]; arr[k] = p; ++c[i]; i = 1; result.push(arr.slice()); } else { c[i] = 0; ++i; } } return result; }
有了 javascript 函数,下一步就是从 Excel 中调用它。感谢 Script Lab,这是一项简单的任务,我创建了一个新的 Snippet,我将其命名为

lib

。然后只是调用它。例如:

为行/列数组输入以及数字或文本数据类型定义的函数按预期工作。我测试了这两个函数以找到

SEQUENCE(8)

的所有排列,即超过
40K
排列并在不到2秒内返回结果(两个javascript公式)。

现在回到最初的问题,它产生了一个非常简单的公式,然后将其向下拖动:

=TEXTJOIN(";",,BYROW(SCRIPTLAB.LIB.PERMUTE(FILTER(A2:E2,A2:E2<>"")), LAMBDA(x, CONCAT(x))))
这里是输出:

此解决方案唯一的不便之处在于,您似乎无法在数组辅助函数(例如

BYROW

)中调用自定义函数。例如以下不起作用:

=BYROW(A2:E4, LAMBDA(x, TEXTJOIN(";",,BYROW(SCRIPTLAB.LIB.PERMUTE(FILTER(x,x<>"")), LAMBDA(y, CONCAT(y))))))
所以你不能生成一个会溢出整个结果的数组版本。您收到以下错误:

希望对您有所帮助,我认为在使用 excel 函数无法提供良好性能或冻结的情况下,这是一个很好的解决方法。

© www.soinside.com 2019 - 2024. All rights reserved.