【问题标题】:Split Lists into Sublists, List.Contains() does not find match将列表拆分为子列表,List.Contains() 找不到匹配项
【发布时间】:2017-08-09 21:30:19
【问题描述】:

我有 2 个列表,PlanetsFavorites。它们包含多个用空格分隔的单词。

我将列表按空格拆分为子列表。

现在我想检查Planets 是否包含来自Favorites 的名称。

但是Planets.Contains() 找不到匹配项。

http://rextester.com/YLOG10363

// Planets List
//
List<string> Planets = new List<string>();
Planets.Add("First Mercury Gray");
Planets.Add("Second Venus Yellow");
Planets.Add("Third Earth Blue");
Planets.Add("Fourth Mars Red");

// Favorites List
//
List<string> Favorites = new List<string>();
Favorites.Add("Venus Hot");
Favorites.Add("Mars Cold");

// Sublists
//
string[] arrPlanets = null;
string[] arrFavorites = null;
List<string> Order = new List<string>();
List<string> Names = new List<string>();
List<string> Colors = new List<string>();



// In each Line of Planets & Favorites Lists, Split by Space
// Add Word to it's Sublist
//
for (int i = 0; i < Planets.Count; i++)
{
    // Create Planet Sublists
    arrPlanets = Convert.ToString(Planets[i]).Split(' ');
    Order.Add(arrPlanets[0]);
    Names.Add(arrPlanets[1]);
    Colors.Add(arrPlanets[2]);

    // Create Favorites Sublist
    // Prevent Favorites index from going out of range
    if (i < Favorites.Count())
    {
        arrFavorites = Convert.ToString(Favorites[i]).Split(' ');

        // Display Message if Planets List Contains a Name from Favorites
        //
        if (Planets.Contains(arrFavorites[0]))
        {
            Console.WriteLine("Favorite Detected.");
        }
    }
}

【问题讨论】:

  • 你为什么在字符串上使用Convert.ToString?此外,我建议您将这些值解析为包含 3 个属性的类,然后使用该类类型的列表。
  • public class Planet { public string Order { set; get; } public string Name { set; get; } public string Color { set; get; } }
  • @juharr 我收到一个错误,说它无法将 char 转换为字符串。但是在重构之后,它似乎无需这样做就可以编译。
  • @juharr 我想我找到了问题区域,Contains 不会在任何列表中找到匹配项,如果它有任何分隔单词的空格。
  • 问题是Planets 不包含完全匹配的字符串。你想要的是Planets.Any(p =&gt; p.Contains(arrFavorites[0])); 但这真的不是一个好主意。如果你有一个 Planet 类,那就是 Planets.Any(p =&gt; p.Name = arrFavorites[0]));

标签: c# arrays list sorting


【解决方案1】:

好的,我已经查看了所有答案,您可能也想看看这种可能性,因为它代表了对您的代码进行最少的重构:

替换

if (Planets.Contains(arrFavorites[0]))

if (Planets.Any(p => p.Contains(arrFavorites[0])))

不是最高效的,因为有更好的算法来检查匹配项。但是看看你的代码,它似乎并不是你所追求的最重要的事情。那么,我的方法可能是有意义的。

希望对您有所帮助。

【讨论】:

    【解决方案2】:

    真的不是很清楚你想要完成什么,但既然你说你想知道Planets是否包含来自Favorites的任何名字,并假设这个名字总是每个收藏夹中的第一个单词,

    var PlanetsHasFavorite = Planets.Any(p => Favorites.Select(f => f.Split(' ')[0]).Any(f => p.Split(' ').Contains(f)));
    

    如果任何行星与来自Favorites 的名称匹配,PlanetsHasFavorite 将为真。

    假设您的意思是您实际上想要获取匹配行星的列表,

    var PlanetsAreFavorite = Planets.Where(p => Favorites.Select(f => f.Split(' ')[0]).Any(f => p.Split(' ').Contains(f))).ToList();
    

    【讨论】:

      【解决方案3】:

      如果要查看某个Favorites中的单词是否包含在某个Planet中,那么只需将Favorites拆分成单词,然后查看某个星球是否包含单词。

      所以,要获得所有最喜欢的词,我们可以这样做:

      var favoriteWords = Favorites.SelectMany(i => i.Split(' '));
      

      现在,我们可以循环遍历所有行星,看看是否有匹配项:

      Planets.ForEach(p =>
      {
          if (favoriteWords.Any(p.Contains))
          {
              Console.WriteLine($"One of your favorite planets is: {p}");
          }
      });
      

      结果是:

      或者,如果您只想显示匹配的最喜欢的单词,您可以执行以下操作:

      Console.WriteLine("These favorite words were matched: ");
      Planets.ForEach(p => favoriteWords.Where(p.Contains).ToList().ForEach(Console.WriteLine));
      

      【讨论】:

        【解决方案4】:

        如果您不知道希望它们保存的项目数,并且不要故意将变量设置为 null,请不要使用数组。 改用列表:

        List<string> planets = new List<string>();
        List<string> favorites = new List<string>(); 
        

        话虽如此,您的代码完全错误。 你想要达到的目标是这样的:

        List<string> Planets = new List<string>();
        Planets.Add("First Mercury Gray");
        Planets.Add("Second Venus Yellow");
        Planets.Add("Third Earth Blue");
        Planets.Add("Fourth Mars Red");
        
        List<string> Favorites = new List<string>();
        Favorites.Add("Venus Hot");
        Favorites.Add("Mars Cold");
        
        // Unless you need favorites to hold tokens seperated by a white space
        // you shouldn't make another list such as this one:
        List<string> faveKeywords = Favorites.SelectMany(fave => fave.Split(' ')).ToList();
        foreach (var token in from line in Planets from token in line.Split(' ') where faveKeywords.Contains(token) select token)
        {
            Console.WriteLine($"Favorite detected: {token}" );
        }
        

        或者,如果您一直坚持下订单、颜色、名称:

        foreach (var tokens in Planets.Select(str => str.Split(' ')))
        {
            Order.Add(tokens[0]);
            Names.Add(tokens[1]);
            Colors.Add(tokens[2]);
            foreach (var token in tokens.Where(token => faveKeywords.Contains(token)))
            {
                Console.WriteLine($"Favorite detected: {token}");
            }
        }
        

        你需要从这个例子中学习,并且观察比你要求的更多。

        【讨论】:

        • 我唯一的问题是,List&lt;T&gt; 的性能不如一个简单的数组。但在负载压力下,差异真的很明显。 底线:没有经验法则。只是需要了解技术权衡是什么。了解技术成本和收益是关键,而不是盲目地遵守“经验法则”。
        • 很抱歉,您关于不将数组设置为 null 的声明在这里无效。 OP 给出的代码清楚地表明了意图,我认为你没有理解。因此:不要依赖经验法则。他们只会给你带来麻烦。最好的结果不是你在这里想的那样。
        猜你喜欢
        • 1970-01-01
        • 2011-03-28
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2019-03-27
        • 2018-10-24
        相关资源
        最近更新 更多