假设我有一个清单:
List<int> _arr = new List<int> {1, 3, 4};
目标为4
我想使用给定列表中的linq将{1, 3}
作为1 + 3 = 4
和{4}
作为4 = 4
返回。
我该怎么做?
答案 0 :(得分:10)
一旦我们有一个方法来获取枚举器/列表的所有子集,这很容易 (见Answer: Most Elegant Way to Get All Subsets of an Array in C#)
using System;
using System.Collections.Generic;
using System.Linq;
public static class Program
{
static void Main(string[] args)
{
var test = new int[] { 1, 2, 3, 4, 5, 6, 7, 8, 9 };
var target = 6;
var matches = from subset in test.SubSetsOf()
where subset.Sum() == target
select subset;
Console.WriteLine("Numbers: {0}", test.Select(i => i.ToString()).Aggregate((a, n) => a + ", " + n));
Console.WriteLine("Target: {0}", target);
foreach (var match in matches)
{
Console.WriteLine(match.Select(m => m.ToString()).Aggregate((a, n) => a + " + " + n) + " = " + target.ToString());
}
Console.ReadKey();
}
public static IEnumerable<IEnumerable<T>> SubSetsOf<T>(this IEnumerable<T> source)
{
// Deal with the case of an empty source (simply return an enumerable containing a single, empty enumerable)
if (!source.Any())
return Enumerable.Repeat(Enumerable.Empty<T>(), 1);
// Grab the first element off of the list
var element = source.Take(1);
// Recurse, to get all subsets of the source, ignoring the first item
var haveNots = SubSetsOf(source.Skip(1));
// Get all those subsets and add the element we removed to them
var haves = haveNots.Select(set => element.Concat(set));
// Finally combine the subsets that didn't include the first item, with those that did.
return haves.Concat(haveNots);
}
}
输出:
Numbers: 1, 2, 3, 4, 5, 6, 7, 8, 9
Target: 6
1 + 2 + 3 = 6
1 + 5 = 6
2 + 4 = 6
6 = 6
答案 1 :(得分:2)
我认为这个问题的最佳解决方案是Dynamic Programming。
创建一个二维数组,其维度为[a + 1,_arr.Length]:
0 1 2 3 4
1
3
4
然后,对于该2D数组中的每一列,填写每个单元格,使列的所有单元格的总和等于列的索引:
0 1 2 3 4
1 0 1 x 0 1
3 0 0 x 1 1
4 0 0 x 0 0
// Alternative solution
0 1 2 3 4
1 0 1 x 0 0
3 0 0 x 1 0
4 0 0 x 0 1
这里,x
表示没有解决方案。此外,第4列有2个解决方案,因此您需要考虑到这一点,可能需要List<int>[a]
?
至于如何填写正好的单元格:
列0
将保留所有零,因为它是一个可以在没有总和的情况下实现的解决方案
对于列i
,您想要i - n
(其中n
是来自_arr的当前数字)
0 1
1 0 1 // 1 - 1 == 0, so you put 1 in here
3 0 0
4 0 0
0 1 2
1 0 1 x // 2 - 1 == 1, 1 already has a solution, but you already used the number necessary to solve 1
3 0 0 x
4 0 0 x
如果您有多个1
s
0 1 2
1 0 1 1 // 1 - 1 == 0
1 0 0 1 // 2 - 1 == 1, 1 already has a solution
3 0 0 0
4 0 0 0
// Alternative solution
0 1 2
1 0 0 1 // 2 - 1 == 1, 1 already has a solution
1 0 1 1 // 1 - 1 == 0
3 0 0 0
4 0 0 0
如果您需要有关动态编程的更多信息:Knapsack Problem Dynamic Programming Algorithm
答案 2 :(得分:1)
我认为你不能使用简单的LINQ查询来做到这一点。事实上,我很难用完整的T-SQL为这个提出一个简单的解决方案!
问题是你试图返回的不是单个项目,而是基于可能的排列而返回各种项目集合。
就此而言,我确实希望有人提出这样的LINQ查询,因为有些事情告诉我它会很棒。 ;)
答案 3 :(得分:1)
如果您正在寻求解决此问题的非常好的快速解决方案,那么您并不孤单。
这是一个众所周知的SUBSET SUM问题。我建议你可以在这里查看维基百科:
http://en.wikipedia.org/wiki/Subset_sum_problem
当然,你可以遍历所有可能的子集来寻找你的总和,但要注意有(2 ^ CountOfListElements)可能的组合。如果列表总是很小,那么编码就没有问题。即使是指数时间解决方案也适用于小型集合。