如何获取字母数组的所有可能模式 [duplicate]

How to get every possible pattern of an array of letters [duplicate]

提问人:John 提问时间:1/11/2012 最后编辑:CœurJohn 更新时间:9/5/2017 访问量:5576

问:

这个问题在这里已经有答案了:
11年前关闭。

可能的重复:
有没有更好的方法来进行字符串的排列?

假设我有字母

a、b、c、d

我想在一个 4 个字母长的字符串中获取这些字母的每一个可能的模式/组合。

AAAA的

巴阿

中国农业协会(CAAA)

达阿

阿巴

阿卡

阿卡德

阿爸

等等。

我可以使用什么循环或模式来列出每个可能的组合?

我是用 C# 编写的,但也欢迎使用 C++ 和 javascript 的示例。

我目前的想法是,每个字母可能增加一个字母。然后向右移动一次并重复。这不包括这样的模式。

阿爸

C# JavaScript 算法

评论

0赞 James Montagne 1/11/2012
总是 4 个字母吗?如果是这样,那就很简单了。
0赞 John 1/11/2012
@liho1eye发布两个 for 循环是没有意义的,因为它不是正确的解决方案。@James不,它可以超过 4 个字母,它的长度可以超过 4 个字母,所以两部分都是动态的。@brian你有什么比搜索旧帖子和发布维基百科链接更好的事情要做吗:T
4赞 phoog 1/11/2012
这与排列不完全是同一个问题。{ 'a', 'b', 'c', 'd' } 的排列不包括字符串 “aaaa”。
1赞 Brian Roach 1/11/2012
@John - 一般来说,它是在帮助人们解决这样的简单问题。我实际上误读了你的问题,以为你在寻找排列,因为这是一个常见的家庭作业问题,可以在这里发布。我很抱歉 - 我没有意识到你只是简单地计算 base4 的数量有问题。
0赞 1/11/2012
@John,您是否需要所有这些排列,或者您可以简单地通过验证您收到的文本是否采用正确的格式?RegEx

答:

7赞 Joe 1/11/2012 #1

这是一个只有一个 for 循环

var one = ['a','b','c','d'];
var length = one.length;
var total = Math.pow(length, length);
var pow3 = Math.pow(length,3);
var pow2 = Math.pow(length,2);

for(var i = 0; i<total; i++)
    console.log(one[Math.floor(i/pow3)], 
        one[Math.floor(i/pow2)%length], 
        one[Math.floor(i/length)%length], 
        one[i%length]);

这是一个简单而低效的方法:

var one = ['a','b','c','d'];
var i,j,k,l;
var len = 4;
for(i=0;i<len;i++) {
    for(j=0;j<len;j++) {
        for(k = 0; k < len; k++) {
            for(l = 0; l<len; l++) {
                console.log(one[i], one[j], one[k], one[l]);
            }
        }
    }
}

类似的 C#:

        var one = new[] {'a','b','c','d'};
        var len = one.Length;

        for(var i=0;i<len;i++) {
            for(var j=0;j<len;j++) {
                for(var k = 0; k < len; k++) {
                    for(var l = 0; l<len; l++) {
                        Console.Write(one[i] +  one[j] + one[k] +  one[l]);
                    }
                }
            }
        }

评论

2赞 Brad Semrad 1/11/2012
这可以仅使用一个数组并引用不同的索引来实现。
3赞 Murat Derya Özen 1/11/2012
你真的不需要 4 个数组吗?
0赞 John 1/11/2012
有趣的是,似乎有效,我只需要清理它
1赞 Fabrizio Calderan 1/11/2012 #2

我使用递归来到了这个 javascript 解决方案。无论如何,这些约束并不昂贵(只有 4^4 次调用)

(function() {
   var combinations = [];

   (function r(s) {
       s = s || '';
       if (s.length === 4) {
          combinations[combinations.length] = s;
          return;
       }
       r(s + 'a');
       r(s + 'b');
       r(s + 'c');
       r(s + 'd');

   })();

   console.log(combinations);
})();

输出为

["aaaa", "aaab", "aaac", "aaad",...., "dddc", "dddd"]
3赞 James Montagne 1/11/2012 #3

只是为了它,这里有一个通用的解决方案,用于 javascript 中任意数量的字母。

http://jsfiddle.net/U9ZkX/

有趣的是,谷歌浏览器想翻译“马来语”的输出。

var letters = ['a', 'b', 'c', 'd'];
var letterCount = letters.length;
var iterations = Math.pow(letterCount, letterCount);

for (var i = 0; i < iterations; i++) {
    var word = "";

    for (var j = 0; j < letterCount; j++) {
        word += letters[Math.floor(i / Math.pow(letterCount, j)) % letterCount];
    }

    document.write(word + "<br>");
}
3赞 ChrisWue 1/11/2012 #4

递归 C# 实现:

public IEnumerable<string> CreateCombinations(IEnumerable<char> input, int length)
{
    foreach (var c in input)
    {
        if (length == 1)
            yield return c.ToString();
        else 
        {
            foreach (var s in CreateCombinations(input, length - 1))
                yield return c.ToString() + s;
        }
    }
}

应允许任意数量的字符和任何所需的字符串长度(直到堆栈溢出:))

使用它:

foreach (var s in CreateCombinations("abcd", 4))
{
    Console.WriteLine(s);
}

结果:

aaaa
aaab
aaac
aaad
aaba
aabb
aabc
aabd
aaca
...
dddd

评论

0赞 Edmund 1/12/2012
这是我会选择的答案。它很容易根据笛卡尔积中的集合数量进行参数化。没有那些丑陋的复制和粘贴循环。:-)
0赞 jamis0n 3/17/2014
这正是我所需要的。@ChrisWue - 你能帮我了解这是在做什么吗?我需要 Javascript 中的相同功能。
0赞 Dagg Nabbit 1/11/2012 #5

一个简单、直接的 javascript 解决方案(用大括号调味):

var letters = ['a', 'b', 'c', 'd'], len=letters.length;

for (var i=len; i--;) 
  for (var j=len; j--;) 
    for (var k=len; k--;) 
      for (var l=len; l--;) 
        console.log (letters[i] + letters[j] + letters[k] + letters[l]);
50赞 Eric Lippert 1/11/2012 #6

使用 LINQ 可以很容易地做到这一点:

string[] items = {"a", "b", "c", "d"};
var query = from i1 in items
            from i2 in items
            from i3 in items
            from i4 in items
            select i1 + i2 + i3 + i4;

foreach(var result in query)
    Console.WriteLine(result);

如果你事先不知道你想要四个的组合,你可以用更多的工作来计算任意笛卡尔积:

http://blogs.msdn.com/b/ericlippert/archive/2010/06/28/computing-a-cartesian-product-with-linq.aspx

评论

1赞 Leandro Bardelli 3/8/2023
我可以在 10 秒内修改它以获得 n 个组合。这太棒了,非常感谢。
0赞 Erik Philips 1/11/2012 #7

使用递归、操作委托和 Lambdas!!(只是为了好玩)

using System;
using System.Collections.Generic;
using System.Linq;

namespace ConsoleApplication4
{
    class Program
    {
        static void Main(string[] args)
        {
            List<char> letters = new List<char>() { 'a', 'b', 'c', 'd' };
            List<string> words = new List<string>();
            Action<IEnumerable<char>, string, List<string>> recursiveLetter = null;

            recursiveLetter = (availLetters, word, newWords) =>
            {
                if (word.Length < availLetters.Count())
                {
                    availLetters.ToList()
                                .ForEach(currentletter => 
                                           recursiveLetter(availLetters, 
                                                           word + currentletter, 
                                                           newWords));
                }
                else
                {
                    newWords.Add(word);
                }
            };

            recursiveLetter(letters, string.Empty, words); // ALL THE MAGIC GO!

            words.ForEach(word => Console.WriteLine(word));
            Console.ReadKey();
        }
    }
}

评论

0赞 ChrisWue 1/11/2012
如果他想打印 3 或 4 个字母的长度 5 的所有组合怎么办?
0赞 Erik Philips 1/11/2012
易于更改,但不是 OP 想要的。
0赞 wye.bee 1/11/2012 #8

C 语言中的实现

#include <stdio.h>
#define WORD_LEN 5
#define ALPHA_LEN 4

char alphabet[ALPHA_LEN] = {'a', 'b', 'c', 'd'};
int w[WORD_LEN] = {};

void print_word() {
    int i;
    char s[WORD_LEN + 1];
    for(i = 0; i < WORD_LEN; i++) {
        s[i] = alphabet[w[i]];
    }
    s[WORD_LEN] = '\0';
    puts(s);
}

int increment_word() {
    int i;
    for(i = 0; i < WORD_LEN; i++) {
        if(w[i] < ALPHA_LEN - 1) {
            w[i]++;
            return 1;
        } else {
            w[i] = 0;
        }
    }
    return 0;
}

int main() {
    int i;
    do {
        print_word();
    } while (increment_word());
}
1赞 Michael 1/11/2012 #9

这也可能会奏效;)

var letters = new[] {'a','b','c','d'};
Random random = new Random();
HashSet<string> results = new HashSet<string>();

while(results.Count < 256) {
    results.Add(letters[random.Next(4)] + letters[random.Next(4)]
              + letters[random.Next(4)] + letters[random.Next(4)]);
}

results.ToList().ForEach(Console.WriteLine);
1赞 ghord 1/11/2012 #10

LINQ 中任何给定 n 的一个衬里:

        var letters = new[] { "a", "b", "c", "d" };
        int n = 4;

        var z = Enumerable.Range(1, n)
            .Select(x => letters.AsEnumerable())
            .Aggregate((g,h) => g.Join(h, _ => true, _ => true, (a, b) => a + b));

评论

0赞 MoizNgp 4/25/2013
我编辑了 int n = 4;至 n = letters.length;
0赞 Scott Brickey 1/11/2012 #11

另一个基于 Linq 的答案:

List<string> items = new List<string>() {"a", "b", "c", "d"};
items.ForEach(i1 => 
  items.ForEach(i2 =>
    items.ForEach(i3 =>
      items.ForEach(i4 =>
        Console.WriteLine(i1 + i2 + i3 + i4)
      )
    )
  )
);
0赞 Luis Casillas 1/12/2012 #12

Haskell很可能是这里最短的程序:

sequence (replicate 4 "abcd")

replicate 4 "abcd"创建一个重复四次的列表。 是一种非常通用的、多态的、moadic 操作,具有多种用途,其中包括生成列表列表的笛卡尔积。"abcd"sequence

可以在 C# 或其他 .NET 语言中复制此解决方案。Eric Lippert 的 LINQ 解决方案与此 Haskell 解决方案相对应:

items = ["a", "b", "c", "d"]

query = do i1 <- items
           i2 <- items
           i3 <- items
           i4 <- items
           return (i1 ++ i2 ++ i3 ++ i4)

如果比较它们,请注意 LINQ 的灵感来自 Haskell 的 ,而 LINQ 的 是 Haskell 的 。from ... in<-selectreturn

Haskell单行解决方案与较长解决方案之间的关系可以通过编写我们自己的定义来揭示:sequence

sequence' [] = return []
sequence' (m:ms) = do x <- m
                      xs <- sequence' ms
                      return (x:xs)

在 LINQ 术语中,该函数允许您将重复的语句替换为从中选择每个项的列表列表。sequencefrom ix in items

编辑:一个朋友刚刚在一行中击败了我(好吧,除了一行):import

import Control.Monad

replicateM 4 "abcd"
0赞 user1144307 1/12/2012 #13

在 Python 中:

项目 = [“a”, “b”, “c”, “d”]

打印 [A + B + C+ D 论坛 in 项目 对于项目中的 B 对于 C in Items 对于 d in items]

1赞 Kerrek SB 1/12/2012 #14

你有一个有 2 2 个字母的字母表,所以每个字母正好表示2 位,因此字母表示 8 位。现在,枚举所有值是一个简单的问题。在 pCeudocode 中:

static const char alphabet[4] = { 'a', 'b', 'c', 'd' };

for (unsigned int i = 0; i != 256; ++i)
{
    for (unsigned int k = 0; k != 4; ++k)
    {
        print(alphabet[(i >> (2*k)) % 4]);
    }
}

这里 256 = 22 × 4,所以你可以很容易地推广这个方案。

0赞 thierry.henrio 1/12/2012 #15

必须有一个 erlang 列表理解

类似的东西

Value = "abcd".
[ [A] ++ [B] ++ [C] ++ [D] || A <- Value, B <- Value, C <- Value, D <- Value ].