【发布时间】:2011-08-30 15:21:10
【问题描述】:
我想生成一个包含可变字符列表的字符串的所有可能排列的列表。 例如,如果我有字符串“ABC”,我想要一个包含所有可能变体的列表,例如:A、B、C、AB、BC。
谢谢。
【问题讨论】:
-
AB和BA一样吗?即,你想只生成 AB 还是生成 AB 和 BA?前者打印所有组合,后者打印所有排列。
我想生成一个包含可变字符列表的字符串的所有可能排列的列表。 例如,如果我有字符串“ABC”,我想要一个包含所有可能变体的列表,例如:A、B、C、AB、BC。
谢谢。
【问题讨论】:
很难确切地说出您想要什么,但根据您的示例输出,这里是如何做我认为您在 F# 中所追求的。
let combinations (s:string) =
let rec loop acc i =
seq {
for i in i .. (s.Length - 1) do
let acc = acc + s.[i..i]
yield acc
yield! loop acc (i + 1)
}
loop "" 0
combinations "ABC" |> Seq.toList //["A"; "AB"; "ABC"; "AC"; "B"; "BC"; "C"]
【讨论】:
这是一个 LINQ 版本:
Func<string, IEnumerable<string>> perm = t =>
{
Func<string, string, IEnumerable<string>> perm2 = null;
perm2 =
(t0, t1s) =>
from n in Enumerable.Range(0, t1s.Length)
let c = t1s.Substring(n, 1)
let x = t1s.Remove(n, 1)
let h = t0 + c
from r in (new [] { h, }).Concat(perm2(h, x))
select r;
return perm2("", t);
};
像这样使用它:
var ps = perm("abc");
它会执行惰性计算。
var ps = perm("abcdefghijklmnopqrstuvwxyz").Take(2);
// Only computes two values when executed
【讨论】:
这里将返回给定一串字符的所有排列(不是不同的)。它既不快速也不高效,但它确实有效......
public List<string> permute(string value, string prefix = "")
{
List<string> result = new List<string>();
for (int x=0;x<value.Length;x++)
{
result.Add(prefix + value[x]);
result.AddRange(permute( value.Remove(x, 1), prefix + value[x]));
}
return result;
}
使用方法:
List<string> output = permute("abc");
【讨论】:
在 F# Snippets 上查看此 snippet
【讨论】:
如果您正在按索引查找排列(而不是必须遍历所有排列),您可以使用称为 factoradics (Source) 的编号系统来查找它们。这是来自原文章的代码,具有更强的 C# 风格(原代码非常'C++ish')和泛型。
/// <summary>
/// Permutes the specified atoms; in lexicographical order.
/// </summary>
/// <typeparam name="T">The type of elements.</typeparam>
/// <param name="atoms">The atoms.</param>
/// <param name="index">The index of the permutation to find.</param>
/// <returns>The permutation.</returns>
public static IList<T> Permute<T>(this IList<T> atoms, int index)
{
var result = new T[atoms.Count];
Permute(atoms, result, index);
return result;
}
/// <summary>
/// Permutes the specified atoms; in lexicographical order.
/// </summary>
/// <typeparam name="T">The type of elements.</typeparam>
/// <param name="atoms">The atoms.</param>
/// <param name="target">The array to place the permutation in.</param>
/// <param name="index">The index of the permutation to find.</param>
public static void Permute<T>(this IList<T> atoms, IList<T> target, int index)
{
if (atoms == null)
throw new ArgumentNullException("atoms");
if (target == null)
throw new ArgumentNullException("target");
if (target.Count < atoms.Count)
throw new ArgumentOutOfRangeException("target");
if (index < 0)
throw new ArgumentOutOfRangeException("index");
var order = atoms.Count;
// Step #1 - Find factoradic of k
var perm = new int[order];
for (var j = 1; j <= order; j++)
{
perm[order - j] = index % j;
index /= j;
}
// Step #2 - Convert factoradic[] to numeric permuatation in perm[]
var temp = new int[order];
for (var i = 0; i < order; i++)
{
temp[i] = perm[i] + 1;
perm[i] = 0;
}
perm[order - 1] = 1; // right-most value is set to 1.
for (var i = order - 2; i >= 0; i--)
{
perm[i] = temp[i];
for (var j = i + 1; j < order; j++)
{
if (perm[j] >= perm[i])
perm[j]++;
}
}
// Step #3 - map numeric permutation to string permutation
for (var i = 0; i < order; ++i)
{
target[i] = atoms[perm[i] - 1];
}
}
【讨论】: