如何保证列表包含序列中的每个字符串恰好一次

问题描述:

假设我有一个字符串列表,像这样:如何保证列表<String>包含序列中的每个字符串恰好一次

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) 
{ 
    ???? 
} 

顺序无关紧要。

+0

看到了这个问题:http://*.com/questions/568347/how-do-i-use-linq-to-obtain-a-unique-list-of-properties-from -a-list-of-objects –

+0

对于这些类型或问题,请提供问题和答案,以便您提出的问题以及所得到的内容变得清晰,如果list1为“新”,那么这两个方法将返回什么。列表 {“foo” ,“酒吧”}'我想'新列表 {“酒吧”,“富”}'。 –

这可能不是在速度方面最优的,但两者的查询足够短,以适应在一行,并很容易理解:

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); 
} 

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); 
    } 

这应该是相当有效率:

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. 确保所有候选项都发生在过滤出的集合中。

这里我们说的是Except,IntersectDistinct。我可以使用带表达式的lamba运算符,但它必须遍历每个项目。该功能可用于预定义的功能。

你的第一个方法

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

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

这将使从列表1这是常见的候选列表中的任何元素,也可以为你的第二个做到这一点的其他方式

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

方法

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

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

candidates.Except(list1).AsEnumerable(); 

如何使用HashSet而不是List?

+0

这对于更大的列表会更有效。 – MrWuf

GroupJoin是工作的正确工具。从msdn

群组加入产生分层的结果,这意味着元件 从外与来自 内匹配元素的集合配对。 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(); 

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; 
}