7

假设我有一个字符串列表,如下所示:

var candidates = new List<String> { "Peter", "Chris", "Maggie", "Virginia" };

现在我想验证另一个List<String>,我们称之为它list1,包含这些候选人中的每一个恰好一次。简洁地说,我该怎么做?我想我可以使用Intersect(). 我也想得到失踪的候选人。

private bool ContainsAllCandidatesOnce(List<String> list1)
{
     ????
}


private IEnumerable<String> MissingCandidates(List<String> list1)
{
     ????
}

顺序无所谓。

4

7 回答 7

5

这在速度方面可能不是最佳的,但是两个查询都足够短,可以放在一行中,并且很容易理解:

private bool ContainsAllCandidatesOnce(List<String> list1)
{
    return candidates.All(c => list1.Count(v => v == c) == 1);
}

private IEnumerable<String> MissingCandidates(List<String> list1)
{
    return candidates.Where(c => list1.Count(v => v == c) != 1);
}
于 2012-05-09T00:11:01.080 回答
2

在这里,我们谈论的是exceptIntersectDistinct。我本可以使用带有表达式的 Lamba 运算符,但它必须遍历每个项目。该功能可通过预定义的功能获得。

对于您的第一种方法

var candidates = new List<String> { "Peter", "Chris", "Maggie", "Virginia" };

private bool ContainsAllCandidatesOnce(List<String> list1)
{
    list1.Intersect(candidates).Distinct().Any();
}

这将给出 list1 中候选列表中常见的任何元素,或者您可以以其他方式执行此操作

candidates.Intersect(list1).Distinct().Any();

对于你的第二种方法

private IEnumerable<String> MissingCandidates(List<String> list1)
{
    list1.Except(candidates).AsEnumerable();
}

这将从 list1 中删除候选中的所有元素。如果你想要它的另一种方式,你可以做

candidates.Except(list1).AsEnumerable();
于 2012-05-09T00:58:12.620 回答
1

GroupJoin 是适合这项工作的工具。来自msdn

GroupJoin 产生分层结果,这意味着来自外部的元素与来自内部的匹配元素的集合配对。GroupJoin 使您能够将结果基于外部每个元素的一整套匹配。

如果给定的外部元素在内部没有相关元素,则该元素的匹配序列将为空,但仍会出现在结果中。

因此,GroupJoin 将为源中的每个项目从目标中找到任何匹配项。如果在目标中未找到匹配项,则不会过滤源中的项目。相反,它们被匹配到一个空组。

Dictionary<string, int> counts = candidates
 .GroupJoin(
   list1,
   c => c,
   s => s,
   (c, g) => new { Key = c, Count = g.Count()
 )
 .ToDictionary(x => x.Key, x => x.Count);

List<string> missing = counts.Keys
  .Where(key => counts[key] == 0)
  .ToList();

List<string> tooMany = counts.Keys
  .Where(key => 1 < counts[key])
  .ToList();
于 2012-05-09T14:14:22.193 回答
1

这应该非常有效:

IEnumerable<string> strings  = ...

var uniqueStrings = from str in strings
                    group str by str into g
                    where g.Count() == 1
                    select g.Key;

var missingCandidates = candidates.Except(uniqueStrings).ToList();
bool isValid = !missingCandidates.Any();
  1. 过滤掉重复。
  2. 确保所有候选人都出现在过滤出的集合中。
于 2012-05-09T00:12:55.870 回答
0

使用 HashSet 代替 List 怎么样?

于 2012-05-09T01:51:52.140 回答
0
    private bool ContainsAllCandidatesOnce(List<String> list1)
    {
        return list1.Where(s => candidates.Contains(s)).Count() == candidates.Count();
    }

    private IEnumerable<String> MissingCandidates(List<String> list1) 
    {
        return candidates.Where(s => list1.Count(c => c == s) != 1);
    } 
于 2012-05-09T00:09:27.433 回答
-1
private static bool ContainsAllCandidatesOnce(List<string> lotsOfCandidates)
{
    foreach (string candidate in allCandidates)
    {
        if (lotsOfCandidates.Count(t => t.Equals(candidate)) != 1)
        {
            return false;
        }
    }

    return true;
}

private static IEnumerable<string> MissingCandidates(List<string> lotsOfCandidates)
{
    List<string> missingCandidates = new List<string>();

    foreach (string candidate in allCandidates)
    {
        if (lotsOfCandidates.Count(t => t.Equals(candidate)) != 1)
        {
            missingCandidates.Add(candidate);
        }
    }

    return missingCandidates;
}
于 2012-05-10T03:08:37.887 回答