簡體   English   中英

如何列出所有排列而不重復?

[英]How to list all permutations without repetition?

當前帖子是此鏈接帖子的后續問題:

將一副 7 張假設的交易卡洗牌,並在 Google 表格中列出他們可以進來的訂單

驚喜。 我的問題孩子實際上是為真女神轉生 3 排列 - 為一個視頻游戲。 我認為把它放在交易卡的術語中對外行來說更有意義。 對不起。

大排列......現在處理它!

好的。 我弄亂了一個包含 7 個獨特怪物的數據集(在視頻游戲早期很容易獲得的初始集)。 它們不能在我的派對中復制,但可以組合成不同的。 一開始,視頻游戲中只有 8 個可用於怪物的插槽。

該項目的重點是構建“融合鏈”的所有排列,試圖將這些怪物排列成獨特的順序,以便稍后在該鏈中組合。

它從 A+B 開始,然后清理該列表以從初始配對中消除任何 B+A 場景(融合 A+B 或 B+A 會產生相同的結果)。 然后,融合只是將 C、D、E、F、G 和 H(當前已損壞)添加到先前融合的結果,直到不再存在可能的融合(我的隊伍中只有一個怪物)。

問題是這樣的:排列單元格中的查詢或其他函數在嘗試列出一次排序 8 個怪物的排列時拋出錯誤“結果數組太大”——甚至在融合發生之前。 我已將問題隔離到這個公式(有點長):

=iferror(if(counta($A$2:$A$13)>=2,arrayformula(query(query(split(flatten(flatten(flatten(flatten(flatten(flatten(
filter($F$2:$F,$F$2:$F<>"")&if(counta($A$2:$A$13)>=3,","&transpose(
filter($A$2:$A$13,$A$2:$A$13<>"")),""))&if(counta($A$2:$A$13)>=4,","&transpose(
filter($A$2:$A$13,$A$2:$A$13<>"")),""))&if(counta($A$2:$A$13)>=5,","&transpose(
filter($A$2:$A$13,$A$2:$A$13<>"")),""))&if(counta($A$2:$A$13)>=6,","&transpose(
filter($A$2:$A$13,$A$2:$A$13<>"")),""))&if(counta($A$2:$A$13)>=7,","&transpose(
filter($A$2:$A$13,$A$2:$A$13<>"")),""))&if(counta($A$2:$A$13)>=8,","&transpose(
filter($A$2:$A$13,$A$2:$A$13<>"")),"")),","),
"where Col1 <> Col2"&
if(counta($A$2:$A$13)>=3," and Col1 <> Col3 and Col2 <> Col3"&
if(counta($A$2:$A$13)>=4," and Col1 <> Col4 and Col2 <> Col4 and Col3 <> Col4"&
if(counta($A$2:$A$13)>=5," and Col1 <> Col5 and Col2 <> Col5 and Col3 <> Col5 and Col4 <> Col5"&
if(counta($A$2:$A$13)>=6," and Col1 <> Col6 and Col2 <> Col6 and Col3 <> Col6 and Col4 <> Col6 and Col5 <> Col6"&
if(counta($A$2:$A$13)>=7," and Col1 <> Col7 and Col2 <> Col7 and Col3 <> Col7 and Col4 <> Col7 and Col5 <> Col7 and Col6 <> Col7"&
if(counta($A$2:$A$13)>=8," and Col1 <> Col8 and Col2 <> Col8 and Col3 <> Col8 and Col4 <> Col8 and Col5 <> Col8 and Col6 <> Col8 and Col7 <> Col8",),),),),),),0),"where Col1 <>''",0)),"not enough data"),)

該公式查看的第一個范圍是以前穩定的形式(F 列):

唯一的初始化對
小精靈,式神
兒玉,小精靈
花婆,小精靈
Datsue-Ba,Pixie
天使,小精靈
Fomorian,小精靈
兒玉式神
花坡,式神
達江場式神
天使,式神
佛摩人,式神
花寶,兒玉
達江場,兒玉
天使,兒玉
佛摩里安,兒玉
達采霸,華坡
天使,華寶
Fomorian,華坡
天使,達江霸
達江壩,佛摩里安
天使,佛摩人

它是由我制作的一種“更清潔”的公式提供的,但這不是問題。

我正在測試的整體輸入是這樣的(在 A 列中),也是初始對的更清晰公式的輸入:

可用的
小精靈
式神
兒玉
華坡
達江壩
天使
福莫里安
高精靈

而預期的 output... 真的很大。 這是獲得想法的第一行示例(托管在原始工作表的 H2 中):

一個 C D F G H
小精靈 式神 兒玉 華坡 達江壩 天使 福莫里安 高精靈
小精靈 式神 兒玉 華坡 達江壩 福莫里安 天使 高精靈
小精靈 式神 兒玉 華坡 天使 達江壩 福莫里安 高精靈
小精靈 式神 兒玉 華坡 天使 福莫里安 達江壩 高精靈
小精靈 式神 兒玉 華坡 福莫里安 達江壩 天使 高精靈
小精靈 式神 兒玉 華坡 福莫里安 天使 達江壩 高精靈
小精靈 式神 兒玉 達江壩 華坡 天使 福莫里安 高精靈
等等...

我目前不知道如何解決這個問題。 我想在我的表格中放置至少 8 個起始怪物以供分析,如果不是完整的 12 個以供游戲結束。

可能有一種比我現有的方式更好、更緊湊的方式來生成這些排列。 我可能想啟動 Excel 在我的超級系統上嘗試這個,然后看看它在哪里斷線。 然而,我想要更有效的公式來解決我在 Google 表格中的“數組太大”問題。 這是我工作得最好的地方,也是我有許多其他項目的地方。

PS:感謝 Erik 對完整工作表的幫助,並教我一些使用 LAMBDA 和命名函數的新技術。 它有助於最終解決我的問題。 Stack 的政策限制我共享完整的電子表格是有充分理由的(擔心不良行為者等等)。 因此,我對這篇文章進行了編輯,以使其更好地包含在內。 再次,為混亂感到抱歉。

Stack 是一項免費的、由志願者運營的服務,旨在提供“小幫助”(例如,一些共享知識、對現有公式或幾乎正確的代碼行的調整等)。 它的設計初衷不是讓人們可以免費獲得定制的、復雜的、耗時的解決方案。

也就是說,由於最近推出的新功能,我選擇采用它,主要是為了展示其中一些新功能的一些好處。

我提供這個解決方案沒有解釋,因為解釋比寫公式要花更長的時間。

我已將以下公式放在鏈接電子表格中新工作表(“Erik 幫助”)的單元格 A1 中:

=ArrayFormula(IFERROR(TO_TEXT(VLOOKUP(SPLIT(REGEXREPLACE({LAMBDA(x,FILTER(x,NOT(REGEXMATCH(x&"","8|9|0")),x>=12,BYROW(1*(MID(x&LEFT("abc",5-LEN(x)),SEQUENCE(1,4),1)<MID(x&LEFT("abc",5-LEN(x)),SEQUENCE(1,4,2),1)),LAMBDA(row,SUM(row)))=4))(SEQUENCE(34567));REGEXREPLACE("1234567",SEQUENCE(7)&"","")*1;1234567}&"","(.)","$1~"),"~",1,1),{SEQUENCE(7),'chains-original':A2,A8},2,FALSE))))

注意新函數 LAMBDA 和 BYROW 的使用。

為了未來訪問者的利益,如果鏈接的電子表格失效,這是公式中與電子表格無關的部分,將生成數字 1-7 的所有唯一組合,即 2 到 7 個數字的組合和在任何單個結果中不重復任何數字:

=ArrayFormula(SPLIT(REGEXREPLACE({LAMBDA(x,FILTER(x,NOT(REGEXMATCH(x&"","8|9|0")),x>=12,BYROW(1*(MID(x&LEFT("abc",5-LEN(x)),SEQUENCE(1,4),1)<MID(x&LEFT("abc",5-LEN(x)),SEQUENCE(1,4,2),1)),LAMBDA(row,SUM(row)))=4))(SEQUENCE(34567));REGEXREPLACE("1234567",SEQUENCE(7)&"","")*1;1234567}&"","(.)","$1~"),"~",1,1))

如果其他人對此公式的特定元素有具體問題,請在下面的評論中提出該問題,我將盡我所能在合理范圍內回答。 但是,我建議首先使用公式(本段上方與電子表格無關的公式)並對其進行剖析以進行理解。 經驗永遠是最好的老師。

有不同的算法來實現這一點。 請參閱計算中的排列

直接且最簡單的方法是創建一個數字序列,其中BASE等於可供選擇的項目數。 例如,如果有 7 個項目可供選擇,請創建如下序列:

BASE 7(=數組公式(BASE(SEQUENCE(25),7,7)))
0000001
0000002
0000003
0000004
0000005
0000006
0000010
0000011
0000012
0000013
0000014
0000015
0000016
0000020
0000021
0000022
0000023
0000024
0000025
0000026
0000030
0000031
0000032
0000033
0000034
……

注意每個 position 有 7 個變量(0 到 6),有 7 個位置。 一旦我們得到了PERMUTATIONA(7,7)的所有數字,只需刪除所有重復的數字就很簡單了,其中每個 position 中的所有數字都是唯一的,即每個數字的COUNTUNIQUE = 7(例如:0124536)。 這是一個實現:

=ARRAYFORMULA(LAMBDA(n,QUERY(BYROW(SPLIT(REGEXREPLACE(TO_TEXT(BASE(SEQUENCE(PERMUTATIONA(n,n)-1),n,n)),"\B","."),"."),LAMBDA(r, IF(COUNTUNIQUE(r)<>n,"👀",JOIN(,r)))),"where not Col1='👀' ",0))(5))

不幸的是,谷歌任意限制執行時間少於幾秒鍾。 因此,此公式無法獲得超過n=5的所有排列。

列表中的下一個是使用階乘(Lehmer 的代碼)來獲取排列。 請參閱此處的排列 請注意數字序列與排列之間的直接關系。

十進制 因數 排列
0 0:0:0! (0,1,2)
1 0:1:0! (0,2,1)
2 1:0:0! (1,0,2)
3 1:1:0! (1,2,0)
4 2:0:0! (2,0,1)
5 2:1:0! (2,1,0)

表格來自https://wikipedia.org/wiki/Factorial_number_system在 CC-BY-SA 3.0 下獲得許可

我實現了這個算法,並且在n=5處再次達到了 Google 的限制。 (此處未顯示代碼)。

接下來,我們有Lexicographic ordering 算法如下:

以下算法在給定排列之后按字典順序生成下一個排列。 它就地改變了給定的排列。

找到滿足 a[k] < a[k + 1] 的最大索引 k。 如果不存在這樣的索引,則排列是最后一個排列。 找到大於 k 的最大索引 l,使得 a[k] < a[l]。 將 a[k] 的值與 a[l] 的值交換。 反轉從 a[k + 1] 到最后一個元素 a[n] 的序列。

例如,給定序列 [1, 2, 3, 4](按升序排列),並且給定索引是從零開始的,步驟如下:

索引 k = 2,因為 3 被放置在滿足仍然小於 a[k + 1] 即 4 的最大索引條件的索引處。索引 l = 3,因為 4 是序列中唯一的值大於 3 以滿足條件 a[k] < a[l]。 a[2] 和 a[3] 的值被交換以形成新的序列 [1, 2, 4, 3]。 從 k-index a[2] 到最后一個元素的順序是相反的。 因為只有一個值位於該索引(3)之后,所以在這種情況下序列保持不變。 因此,初始 state 的詞典后繼被置換:[1,2,4,3]。

引自https://en.wikipedia.org/wiki/Permutation根據 CC-BY-SA 3.0 許可

感謝 Google 對遞歸和命名函數的最新支持,我實現了這一點,並且能夠在單個公式中獲得多達n=6 (720 項),但我仍然達到了 Google 的遞歸限制,即n=7 (5040 項) . 話雖如此,仍然可以在沒有數組公式的情況下一一獲得所有 5k 排列(甚至可能n=8 (40320 項),具體取決於您的設備可以處理的內容)。

1.小精靈 2.式神 3.兒玉 4.花婆 5.達江壩 6.天使 7.佛摩里安
1.小精靈 2.式神 3.兒玉 4.花婆 5.達江壩 7.佛摩里安 6.天使
1.小精靈 2.式神 3.兒玉 4.花婆 6.天使 5.達江壩 7.佛摩里安
1.小精靈 2.式神 3.兒玉 4.花婆 6.天使 7.佛摩里安 5.達江壩
1.小精靈 2.式神 3.兒玉 4.花婆 7.佛摩里安 5.達江壩 6.天使
1.小精靈 2.式神 3.兒玉 4.花婆 7.佛摩里安 6.天使 5.達江壩
1.小精靈 2.式神 3.兒玉 5.達江壩 4.花婆 6.天使 7.佛摩里安
1.小精靈 2.式神 3.兒玉 5.達江壩 4.花婆 7.佛摩里安 6.天使
1.小精靈 2.式神 3.兒玉 5.達江壩 6.天使 4.花婆 7.佛摩里安
1.小精靈 2.式神 3.兒玉 5.達江壩 6.天使 7.佛摩里安 4.花婆
1.小精靈 2.式神 3.兒玉 5.達江壩 7.佛摩里安 4.花婆 6.天使
1.小精靈 2.式神 3.兒玉 5.達江壩 7.佛摩里安 6.天使 4.花婆
1.小精靈 2.式神 3.兒玉 6.天使 4.花婆 5.達江壩 7.佛摩里安
1.小精靈 2.式神 3.兒玉 6.天使 4.花婆 7.佛摩里安 5.達江壩
1.小精靈 2.式神 3.兒玉 6.天使 5.達江壩 4.花婆 7.佛摩里安
1.小精靈 2.式神 3.兒玉 6.天使 5.達江壩 7.佛摩里安 4.花婆
1.小精靈 2.式神 3.兒玉 6.天使 7.佛摩里安 4.花婆 5.達江壩
1.小精靈 2.式神 3.兒玉 6.天使 7.佛摩里安 5.達江壩 4.花婆
1.小精靈 2.式神 3.兒玉 7.佛摩里安 4.花婆 5.達江壩 6.天使
1.小精靈 2.式神 3.兒玉 7.佛摩里安 4.花婆 6.天使 5.達江壩
1.小精靈 2.式神 3.兒玉 7.佛摩里安 5.達江壩 4.花婆 6.天使
1.小精靈 2.式神 3.兒玉 7.佛摩里安 5.達江壩 6.天使 4.花婆
1.小精靈 2.式神 3.兒玉 7.佛摩里安 6.天使 4.花婆 5.達江壩
1.小精靈 2.式神 3.兒玉 7.佛摩里安 6.天使 5.達江壩 4.花婆

顯示n=7的前幾個排列。 要使公式起作用,請務必注意列表中必須存在固有的升序。 我在1.Pixie2.Shikigami ... 等中添加了前綴: 1.2.等,以強制執行升序 可以在公式本身中進行排序,但未實現。

  • A1:G1

    1.小精靈 2.式神 3.兒玉 4.花婆 5.達江壩 6.天使 7.佛摩里安
  • A2

     =GET_NEXT_LEX(A1:G1)

根據需要向下拖動填充或自動填充(40k 或 5k 行)。

命名函數:

創建這些函數

主要function:

  • GET_NEXT_LEX(arr)
=ARRAYFORMULA(
  TRANSPOSE(
    LAMBDA(arr,     
      LAMBDA(k,       
        LAMBDA(sarr,k,{SPLICE(sarr,k+1,2^999);REVERSE(SPLICE(sarr,1,k+1))})  
          (SWAP(arr,k,XMATCH(TRUE,INDEX(arr,k)<SPLICE(arr,1,k+1),,-1)+k),k)
      )(XMATCH(TRUE,POP(arr)<SHIFT(arr),,-1))
    )(TRANSPOSE(arr))
  )
)

輔助功能:

功能類似於

  • SPLICE(arr,i,j)
=FILTER(arr,LAMBDA(seq,(seq<i)+(seq>=j))(SEQUENCE(ROWS(arr))))
  • REVERSE(arr)
=POP(REDUCE(,arr,LAMBDA(a,c,{c;a})))
  • SWAP(arr,i,j)
=SORT(arr,LAMBDA(keys,SWITCH(keys,i,j,j,i,keys))(SEQUENCE(ROWS(arr))),1)
  • POP(arr)
=ARRAY_CONSTRAIN(arr,ROWS(arr)-1,1)
  • SHIFT(arr)
=FILTER(arr,{0;SEQUENCE(ROWS(arr)-1)})

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM