C#或Javascript多次排列两个数组

时间:2014-01-10 12:48:19

标签: c# arrays permutation concat

我一直在工作,放弃然后重新处理这个问题几天。我已经看了很多不同的方法,但是我要么无法正确实现它,要么不适合我需要做的事情。

基本上:我有两个数组,前缀和后缀

 prefix = { 0, 0, 3, 8, 8, 15} 
 suffix = { 0, 3, 2, 7, 7, 9, 12, 15 }

我需要:

  • 至少使用3个组合(2 + 1或1 + 2),最多使用6个(3 + 3)。
  • 不要多次使用词缀(除非它重复(即前缀中有两个8))

最终目标是查看哪些组合可以等于X.

例如

X = 42
3 + 8 + 8 + 2 + 9 + 12 = 42
0 + 8 + 8 + 7 + 7 + 12 = 42
| Prefix |  | Suffix |

15 + 12 + 15 = 42
0 + 15 + 0 + 12 + 15 = 42

我已经尝试过研究Permutations,IEnumerables,Concat等等,但找不到能成功做到这一点的东西。

这些是我需要使用的“完整”数组。

public int[] Prefix = {0, 6, 6, 8, 8, 8, 8, 8, 8, 11, 12, 12, 12, 12, 12, 12, 12, 12, 12, 16, 15, 15, 18, 18, 18, 18, 18, 18, 23 };
public int[] Suffix = {0, 3, 3, 9, 11, 11, 11, 17, 18, 18, 20, 25, 25, 27, 30, 30};

任何帮助都表示赞赏,如果我不清楚任何事情我会尽可能地澄清,谢谢!

编辑:我还建议我运行它来等同于所有可能的结果并将其存储在哈希表中,以便在使用正确的值时使用?不确定哪种方法效果最好。

6 个答案:

答案 0 :(得分:2)

采用“OR Javascript”选项......

  1. 创建一个关联数组,将前缀的总数映射到生成该总数的前缀排列数组;然后填充它。
  2. 为后缀创建一个类似的第二个关联数组,但只有expected_result - total位于前缀的关联数组中时,才会使用后缀排列填充它。
  3. 输出有效后缀和相应的前缀。
  4. JSFIDDLE

    // Inputs
    var prefixes = [0, 6, 6, 8, 8, 8, 8, 8, 8, 11, 12, 12, 12, 12, 12, 12, 12, 12, 12, 16, 15, 15, 18, 18, 18, 18, 18, 18, 23],
        suffixes = [0, 3, 3, 9, 11, 11, 11, 17, 18, 18, 20, 25, 25, 27, 30, 30],
        expected_result = 42;
    
    // Associative Arrays
    var prefixTotals = {},
        suffixTotals = {},
    // Functions
        addTotal     = function( map, arr, other_map ){
            var t = 0, i = 0;
            for ( ; i < arr.length; ++i )
                t += arr[i].value;
            if (   ( other_map === undefined )
                || ( ( expected_result - t ) in other_map ) )
            {
                if ( !( t in map ) )
                    map[t] = [];
                map[t].push( arr );
            }
        },
        calcPermutations     = function( affixes, map, other_map ) {
            var i = 0, j, k, l = affixes.length;
            for ( ; i < l; ++i )
            {
                addTotal( map, [ { index: i, value: affixes[i] } ], other_map );
                for ( j = i+1; j < l; ++j )
                {
                    addTotal( map, [ { index: i, value: affixes[i] }, { index: j, value: affixes[j] } ], other_map );
                    for ( k = j+1; k < l; ++k )
                    {
                        addTotal( map, [ { index: i, value: affixes[i] }, { index: j, value: affixes[j] }, { index: k, value: affixes[k] } ], other_map );
                    }
                }
            }
        },
        resultToString = function( affixes ){
            var s = [];
            for ( var i = 0; i < affixes.length; ++i )
                s.push( affixes[i].index + '=>' + affixes[i].value );
            return s.join(',');
        };
    
    calcPermutations( prefixes, prefixTotals, undefined );
    calcPermutations( suffixes, suffixTotals, prefixTotals );
    
    var i,j,k,p,s,count = 0,html=[];
    for ( i in suffixTotals )
    {
        s = suffixTotals[i];
        p = prefixTotals[expected_result - i];
        for ( j = 0; j < p.length; ++j )
            for ( k = 0; k < s.length; ++k )
                html.push( 'Prefixes [' + resultToString( p[j] ) + '], Suffixes [' + resultToString( s[k] ) + ']' );
        count += p.length * s.length;
    }
    html.unshift( 'There were ' + count + ' valid permutations:' );
    
    document.getElementById( 'out' ).innerHTML = html.join( '<br />' );
    

答案 1 :(得分:1)

正如所建议的,你当然可以嵌套循环直到Pascal抱怨他的三角形,但如果你愿意,你也可以采取完全概率的方法:)

毕竟,当蛮力解决方案正在执行时,a rogue alpha particle can flip an entire bit in the memory cells无论如何也无法提出正确答案。 (这是一个笑话。请不要向我投降,让宇宙射线击中SO服务器来处理它。)

42 ==  
  prefix.OrderBy(x => random.Next(0,prefix.Length)).Take(random.Next(1,4)).Sum() 
  + 
  suffix.OrderBy(x => random.Next(0,suffix.Length)).Take(random.Next(1,4)).Sum();

这是一个演示,

using System;
using System.Linq;

namespace WhatWasTheQuestion {
    class Program {
        static readonly int[] prefix = { 0, 0, 3, 8, 8, 15 };
        static readonly int[] suffix = { 0, 3, 2, 7, 7, 9, 12, 15 };
        static readonly Random random = new Random();

        static bool generateAndCheckCandidate(int X) {
            var prefixCandidates = prefix.OrderBy(x => random.Next(0, prefix.Length)).Take(random.Next(1, 4)).ToList();
            var suffixCandidates = suffix.OrderBy(x => random.Next(0, suffix.Length)).Take(random.Next(1, 4)).ToList();
            if (prefixCandidates.Sum() + suffixCandidates.Sum() == X) {
                Console.WriteLine(X + " = "  + String.Join("+", prefixCandidates) + "+" + String.Join("+", suffixCandidates));
                return true;
            }
            return false;
        }

        static void Main(string[] args) {
            int maxAttempts = 10000;
            while (maxAttempts > 0 && !generateAndCheckCandidate(42))
            {
                --maxAttempts;
            }
        }
    }
}
// Output:
// 42 = 8+15+0+0+7+12+0

答案 2 :(得分:1)

这是一个使用LINQ的直观(虽然很慢)的解决方案:

int[] prefixes = { 0, 0, 3, 8, 8, 15 };
int[] suffixes = { 0, 3, 2, 7, 7, 9, 12, 15 };
int target = 42;

var results =
    from prefixLength in Enumerable.Range(1, 3)
    from suffixLength in Enumerable.Range(1, 3)
    where prefixLength + suffixLength >= 3
    from prefixPermutation in prefixes.GetPermutations(prefixLength)
    from suffixPermutation in suffixes.GetPermutations(suffixLength)
    let affixPermutation = prefixPermutation.Concat(suffixPermutation)
    where affixPermutation.Sum() == target
    select string.Join(" + ", affixPermutation);

var final = results.Distinct().ToArray();

我使用了一些基本的可枚举扩展:

public static partial class EnumerableExtensions
{
    public static IEnumerable<IEnumerable<T>> GetPermutations<T>(this IEnumerable<T> source, int length)
    {
        if (length == 0)
        {
            yield return Enumerable.Empty<T>();
            yield break;
        }

        int index = 0;
        foreach (T item in source)
        {
            IEnumerable<T> remainder = source.ExceptAt(index);
            IEnumerable<IEnumerable<T>> tails = GetPermutations(remainder, length - 1);
            foreach (IEnumerable<T> tail in tails)
                yield return tail.Prepend(item);
            index++;
        }
    }

    public static IEnumerable<T> ExceptAt<T>(this IEnumerable<T> source, int index)
    {
        return source.Take(index).Concat(source.Skip(index + 1));
    }

    public static IEnumerable<T> Prepend<T>(this IEnumerable<T> source, T first)
    {
        yield return first;
        foreach (T item in source)
            yield return item;
    }
}

答案 3 :(得分:1)

对于那么多代码感到抱歉。它不是印度人,完全100%工作:

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

namespace ConsoleApplication1
{
    static class Program
    {
        static void Main(string[] args)
        {
            Console.Write("Sum: ");

            var sum = int.Parse(Console.ReadLine());

            var prefix = new[] { 1, 2, 3, 4, 5, 6 };
            var suffix = new[] { 0, 3, 2, 7, 7, 9, 12, 15 };

            foreach (var item in Solution(prefix, suffix, 1, 3, sum))
            {
                Console.WriteLine("{0} = [ {1} ] + [ {2} ]", sum, string.Join(" + ", item.Item1.Select(T => prefix[T])), string.Join(" + ", item.Item2.Select(T => suffix[T])));
            }

            Console.WriteLine("Done here. Any key to close.");
            Console.ReadKey();
        }

        public static IEnumerable<Tuple<int[], int[]>> Solution(int[] one, int[] two, int minElementCount, int maxElementCount, int sum)
        {
            if (one.Length < minElementCount || two.Length < minElementCount)
            {
                throw new Exception("Nah.");
            }

            var cacheOne = new Dictionary<int, List<int[]>>();
            var cacheTwo = new Dictionary<int, List<int[]>>();
            var result = new List<Tuple<int[], int[]>>();

            for (int countInOne = minElementCount; countInOne <= Math.Min(one.Length, maxElementCount); countInOne++)
            {
                for (int countInTwo = minElementCount; countInTwo <= Math.Min(two.Length, maxElementCount); countInTwo++)
                {
                    List<int[]> permutationsOne;
                    List<int[]> permutationsTwo;

                    if (!cacheOne.TryGetValue(countInOne, out permutationsOne))
                    {
                        permutationsOne = cacheOne[countInOne] = PermutationsIndices(one, countInOne).ToList();
                    }

                    if (!cacheTwo.TryGetValue(countInTwo, out permutationsTwo))
                    {
                        permutationsTwo = cacheTwo[countInTwo] = PermutationsIndices(two, countInTwo).ToList();
                    }

                    foreach (var permutationOne in permutationsOne)
                    {
                        var sumOne = permutationOne.Select(T => one[T]).Sum();

                        if (sumOne <= sum)
                        {
                            foreach (var permutationTwo in permutationsTwo)
                            {
                                if ((sumOne + permutationTwo.Select(T => two[T]).Sum() == sum))
                                {
                                    yield return Tuple.Create(permutationOne, permutationTwo);
                                }
                            }
                        }
                    }
                }
            }
        }
        public static IEnumerable<int[]> PermutationsIndices<T>(this T[] e, int count)
        {
            if (count > e.Length)
            {
                throw new Exception("Nah.");
            }

            return TraverseArray(e, new Stack<int>(), 0, count - 1);
        }
        public static IEnumerable<int[]> TraverseArray<T>(T[] array, Stack<int> stack, int index, int iterations)
        {
            for (int i = index; i < array.Length - iterations; i++)
            {
                stack.Push(i);

                if (iterations == 0)
                {
                    yield return stack.Reverse().ToArray();
                }
                else
                {
                    foreach (int[] item in TraverseArray(array, stack, i + 1, iterations - 1))
                    {
                        yield return item;
                    }
                }

                stack.Pop();
            }
        }
    }
}

所以,你的任务输出......

prefix = { 0, 0, 3, 8, 8, 15 }
suffix = { 0, 3, 2, 7, 7, 9, 12, 15 }

将是这样:

Sum: 42
42 = [ 15 ] + [ 12 + 15 ]
42 = [ 8 ] + [ 7 + 12 + 15 ]
42 = [ 8 ] + [ 7 + 12 + 15 ]
42 = [ 8 ] + [ 7 + 12 + 15 ]
42 = [ 8 ] + [ 7 + 12 + 15 ]
42 = [ 15 ] + [ 0 + 12 + 15 ]
42 = [ 15 ] + [ 3 + 9 + 15 ]
42 = [ 0 + 15 ] + [ 12 + 15 ]
42 = [ 0 + 15 ] + [ 12 + 15 ]
42 = [ 3 + 15 ] + [ 9 + 15 ]
42 = [ 8 + 15 ] + [ 7 + 12 ]
42 = [ 8 + 15 ] + [ 7 + 12 ]
42 = [ 8 + 15 ] + [ 7 + 12 ]
42 = [ 8 + 15 ] + [ 7 + 12 ]
42 = [ 0 + 8 ] + [ 7 + 12 + 15 ]
42 = [ 0 + 8 ] + [ 7 + 12 + 15 ]
42 = [ 0 + 8 ] + [ 7 + 12 + 15 ]
42 = [ 0 + 8 ] + [ 7 + 12 + 15 ]
42 = [ 0 + 15 ] + [ 0 + 12 + 15 ]
42 = [ 0 + 15 ] + [ 3 + 9 + 15 ]
42 = [ 0 + 8 ] + [ 7 + 12 + 15 ]
42 = [ 0 + 8 ] + [ 7 + 12 + 15 ]
42 = [ 0 + 8 ] + [ 7 + 12 + 15 ]
42 = [ 0 + 8 ] + [ 7 + 12 + 15 ]
42 = [ 0 + 15 ] + [ 0 + 12 + 15 ]
42 = [ 0 + 15 ] + [ 3 + 9 + 15 ]
42 = [ 3 + 8 ] + [ 7 + 9 + 15 ]
42 = [ 3 + 8 ] + [ 7 + 9 + 15 ]
42 = [ 3 + 8 ] + [ 7 + 9 + 15 ]
42 = [ 3 + 8 ] + [ 7 + 9 + 15 ]
42 = [ 3 + 15 ] + [ 0 + 9 + 15 ]
42 = [ 3 + 15 ] + [ 3 + 9 + 12 ]
42 = [ 3 + 15 ] + [ 2 + 7 + 15 ]
42 = [ 3 + 15 ] + [ 2 + 7 + 15 ]
42 = [ 8 + 8 ] + [ 2 + 9 + 15 ]
42 = [ 8 + 8 ] + [ 7 + 7 + 12 ]
42 = [ 8 + 15 ] + [ 0 + 7 + 12 ]
42 = [ 8 + 15 ] + [ 0 + 7 + 12 ]
42 = [ 8 + 15 ] + [ 3 + 7 + 9 ]
42 = [ 8 + 15 ] + [ 3 + 7 + 9 ]
42 = [ 8 + 15 ] + [ 0 + 7 + 12 ]
42 = [ 8 + 15 ] + [ 0 + 7 + 12 ]
42 = [ 8 + 15 ] + [ 3 + 7 + 9 ]
42 = [ 8 + 15 ] + [ 3 + 7 + 9 ]
42 = [ 0 + 0 + 15 ] + [ 12 + 15 ]
42 = [ 0 + 3 + 15 ] + [ 9 + 15 ]
42 = [ 0 + 8 + 15 ] + [ 7 + 12 ]
42 = [ 0 + 8 + 15 ] + [ 7 + 12 ]
42 = [ 0 + 8 + 15 ] + [ 7 + 12 ]
42 = [ 0 + 8 + 15 ] + [ 7 + 12 ]
42 = [ 0 + 3 + 15 ] + [ 9 + 15 ]
42 = [ 0 + 8 + 15 ] + [ 7 + 12 ]
42 = [ 0 + 8 + 15 ] + [ 7 + 12 ]
42 = [ 0 + 8 + 15 ] + [ 7 + 12 ]
42 = [ 0 + 8 + 15 ] + [ 7 + 12 ]
42 = [ 3 + 8 + 15 ] + [ 7 + 9 ]
42 = [ 3 + 8 + 15 ] + [ 7 + 9 ]
42 = [ 3 + 8 + 15 ] + [ 7 + 9 ]
42 = [ 3 + 8 + 15 ] + [ 7 + 9 ]
42 = [ 8 + 8 + 15 ] + [ 2 + 9 ]
42 = [ 0 + 0 + 8 ] + [ 7 + 12 + 15 ]
42 = [ 0 + 0 + 8 ] + [ 7 + 12 + 15 ]
42 = [ 0 + 0 + 8 ] + [ 7 + 12 + 15 ]
42 = [ 0 + 0 + 8 ] + [ 7 + 12 + 15 ]
42 = [ 0 + 0 + 15 ] + [ 0 + 12 + 15 ]
42 = [ 0 + 0 + 15 ] + [ 3 + 9 + 15 ]
42 = [ 0 + 3 + 8 ] + [ 7 + 9 + 15 ]
42 = [ 0 + 3 + 8 ] + [ 7 + 9 + 15 ]
42 = [ 0 + 3 + 8 ] + [ 7 + 9 + 15 ]
42 = [ 0 + 3 + 8 ] + [ 7 + 9 + 15 ]
42 = [ 0 + 3 + 15 ] + [ 0 + 9 + 15 ]
42 = [ 0 + 3 + 15 ] + [ 3 + 9 + 12 ]
42 = [ 0 + 3 + 15 ] + [ 2 + 7 + 15 ]
42 = [ 0 + 3 + 15 ] + [ 2 + 7 + 15 ]
42 = [ 0 + 8 + 8 ] + [ 2 + 9 + 15 ]
42 = [ 0 + 8 + 8 ] + [ 7 + 7 + 12 ]
42 = [ 0 + 8 + 15 ] + [ 0 + 7 + 12 ]
42 = [ 0 + 8 + 15 ] + [ 0 + 7 + 12 ]
42 = [ 0 + 8 + 15 ] + [ 3 + 7 + 9 ]
42 = [ 0 + 8 + 15 ] + [ 3 + 7 + 9 ]
42 = [ 0 + 8 + 15 ] + [ 0 + 7 + 12 ]
42 = [ 0 + 8 + 15 ] + [ 0 + 7 + 12 ]
42 = [ 0 + 8 + 15 ] + [ 3 + 7 + 9 ]
42 = [ 0 + 8 + 15 ] + [ 3 + 7 + 9 ]
42 = [ 0 + 3 + 8 ] + [ 7 + 9 + 15 ]
42 = [ 0 + 3 + 8 ] + [ 7 + 9 + 15 ]
42 = [ 0 + 3 + 8 ] + [ 7 + 9 + 15 ]
42 = [ 0 + 3 + 8 ] + [ 7 + 9 + 15 ]
42 = [ 0 + 3 + 15 ] + [ 0 + 9 + 15 ]
42 = [ 0 + 3 + 15 ] + [ 3 + 9 + 12 ]
42 = [ 0 + 3 + 15 ] + [ 2 + 7 + 15 ]
42 = [ 0 + 3 + 15 ] + [ 2 + 7 + 15 ]
42 = [ 0 + 8 + 8 ] + [ 2 + 9 + 15 ]
42 = [ 0 + 8 + 8 ] + [ 7 + 7 + 12 ]
42 = [ 0 + 8 + 15 ] + [ 0 + 7 + 12 ]
42 = [ 0 + 8 + 15 ] + [ 0 + 7 + 12 ]
42 = [ 0 + 8 + 15 ] + [ 3 + 7 + 9 ]
42 = [ 0 + 8 + 15 ] + [ 3 + 7 + 9 ]
42 = [ 0 + 8 + 15 ] + [ 0 + 7 + 12 ]
42 = [ 0 + 8 + 15 ] + [ 0 + 7 + 12 ]
42 = [ 0 + 8 + 15 ] + [ 3 + 7 + 9 ]
42 = [ 0 + 8 + 15 ] + [ 3 + 7 + 9 ]
42 = [ 3 + 8 + 8 ] + [ 2 + 9 + 12 ]
42 = [ 3 + 8 + 8 ] + [ 7 + 7 + 9 ]
42 = [ 3 + 8 + 15 ] + [ 0 + 7 + 9 ]
42 = [ 3 + 8 + 15 ] + [ 0 + 7 + 9 ]
42 = [ 3 + 8 + 15 ] + [ 2 + 7 + 7 ]
42 = [ 3 + 8 + 15 ] + [ 0 + 7 + 9 ]
42 = [ 3 + 8 + 15 ] + [ 0 + 7 + 9 ]
42 = [ 3 + 8 + 15 ] + [ 2 + 7 + 7 ]
42 = [ 8 + 8 + 15 ] + [ 0 + 2 + 9 ]
Done here. Any key to close.

答案 4 :(得分:0)

这不是一个漂亮的解决方案,但它是一个有效的解决方案。 请注意我如何确保前缀和后缀在开始时都有两个零,以便还包括只使用该数组中的一个或两个值的情况。

    int[] prefix = { 0, 0, 3, 8, 8, 15};
    int[] suffix = { 0, 0, 3, 2, 7, 7, 9, 12, 15 };
    for(int p1 = 0; p1 < prefix.Length; p1++) {
        for(int p2 = 0; p2 < prefix.Length; p2++) {
            for(int p3 = 0; p3 < prefix.Length; p3++) {
                for(int s1 = 0; s1 < suffix.Length; s1++) {
                    for(int s2 = 0; s2 < suffix.Length; s2++) {
                        for(int s3 = 0; s3 < suffix.Length; s3++) {
                            if(prefix[p1] + prefix[p2] + prefix[p3] + suffix[s1] + suffix[s2] + suffix[s3] == 42)
                            {
                                System.Console.WriteLine(string.Format("{0} + {1} + {2} + {3} + {4} + {5} = 42", prefix[p1], prefix[p2], prefix[p3], suffix[s1], suffix[s2], suffix[s3] ));
                            }
                        }
                    }
                }
            }
        }

答案 5 :(得分:0)

这是另一种强制解决方案的替代方案。我不得不在没有LINQ的情况下在.NET 3上编写它,所以我编写了自己的辅助方法来汇总和连接值 - 因此代码量很大。 EnumerateIndicesSum42正在完成所有工作。使用LINQ可以缩短它的速度,但我现在无法访问它,所以在我意外引入任何错误之前,我会留下它来清理它。

public static IEnumerable<int[]> EnumerateIndices(int[] values, int length)
{
    int[] result = new int[length]; 
    int size = (int)(Math.Pow(values.Length, length));
    for(int i = 0; i < size; ++i)
    {
        int tmp = i;
        for(int j = length - 1; j >= 0; --j)
        {
            result[j] = values[tmp % values.Length];
            tmp /= values.Length;               
        }

        yield return result;
    }       
}

public static int Sum(int[] values)
{
    // Just a helper method - if you can use LINQ replace by values.Sum()
    int result = 0, size = values.Length;       
    for(int i = 0; i < size; ++i)
    {
        result += values[i];
    }
    return result;
}

public static string Join(string separator, int[] values)
{
    // Just a helper method, if you can use LINQ replace by sth like string.Join(separator, values.ToArray<string>())
    string[] stringValues = new string[values.Length];  
    int size = values.Length;
    for(int i = 0; i < size; ++i)
    {
        stringValues[i] = values[i].ToString(); 
    }
    return string.Join(separator, stringValues);
}

public static void Sum42()
{
    int[] prefix = { 0, 0, 3, 8, 8, 15};
    int[] suffix = { 0, 3, 2, 7, 7, 9, 12, 15 };

    IEnumerable<int[]> prefixes = EnumerateIndices(prefix, 3);
    IEnumerable<int[]> suffixes = EnumerateIndices(suffix, 3);
    foreach(int[] p in prefixes) {
        foreach(int[] s in suffixes) {
            if(Sum(p) + Sum(s) == 42)
            {
                System.Console.WriteLine("{0} + {1} = 42", Join(" + ", p), Join(" + ", s)); 
            }
        }
    }
}