【问题标题】:Group list of strings with common prefixes具有公共前缀的字符串组列表
【发布时间】:2021-01-13 02:32:09
【问题描述】:

假设我有一个字符串列表[city01, city01002, state02, state03, city04, statebg, countryqw, countrypo]

如何将它们分组到 dictionary<string, List<Strings>>

city - [city01, city04, city01002]
state- [state02, state03, statebg]
country - [countrywq, countrypo]

如果不是代码,谁能帮忙解决或继续?

【问题讨论】:

  • 为什么你认为第一组不会是city0

标签: c# string list linq


【解决方案1】:

如其他答案所示,您可以使用 LINQ 中的 GroupBy 方法根据您想要的任何条件创建此分组。在对字符串进行分组之前,您需要了解字符串如何分组的条件。可能是它以一组预定义前缀中的一个开头,按第一个数字之前的内容或您可以用代码描述的任何随机条件分组。在我的代码示例中,groupBy 方法为列表中的每个字符串调用另一个方法,并且在该方法中,您可以通过返回将给定字符串分组的键来放置所需的代码,以根据需要对字符串进行分组。您可以使用 dotnetfiddle 在线测试此示例:https://dotnetfiddle.net/UHNXvZ

using System;
using System.Collections.Generic;
using System.Linq;
                
public class Program
{
    public static void Main()
    {
        List<string> ungroupedList = new List<string>() {"city01", "city01002", "state02", "state03", "city04", "statebg", "countryqw", "countrypo", "theFirstTown"};
        var groupedStrings = ungroupedList.GroupBy(x => groupingCondition(x));
    
        foreach (var a in groupedStrings) {
            Console.WriteLine("key: " + a.Key);
            foreach (var b in a) {
                Console.WriteLine("value: " + b);
            }
        }
    }

    public static string groupingCondition(String s) {
        if(s.StartsWith("city") || s.EndsWith("Town"))
            return "city";
        if(s.StartsWith("country"))
            return "country";
        if(s.StartsWith("state"))
            return "state";
        return "unknown";
    }
}

【讨论】:

    【解决方案2】:

    您可以使用 LINQ:

     var input = new List<string>()
    { "city01", "city01002", "state02",
       "state03", "city04", "statebg", "countryqw", "countrypo" };
    
    var output = input.GroupBy(c => string.Join("", c.TakeWhile(d => !char.IsDigit(d))
                .Take(4))).ToDictionary(c => c.Key, c => c.ToList());
    

    【讨论】:

      【解决方案3】:

      我想你有一个你在列表中搜索的参考列表:

          var list = new List<string>()
          { "city01", "city01002", "state02",
              "state03", "city04", "statebg", "countryqw", "countrypo" };
      
          var tofound = new List<string>() { "city", "state", "country" }; //references to found
          
      
          var result = new  Dictionary<string, List<string>>();
          foreach (var f in tofound)
          {
              result.Add(f, list.FindAll(x => x.StartsWith(f)));
          }
      

      在结果中,你得到了想要的字典。如果没有为引用键建立值,则键的值为空

      【讨论】:

        【解决方案4】:

        警告:此答案具有组合扩展,如果您的原始字符串集很大,则会失败。跑了几个小时后,我放弃了 65 个字。

        使用一些IEnumerable 扩展方法来查找Distinct 集合并找到所有可能的集合组合,您可以生成一组前缀,然后通过这些前缀对原始字符串进行分组。

        public static class IEnumerableExt {
            public static bool IsDistinct<T>(this IEnumerable<T> items) {
                var hs = new HashSet<T>();
                foreach (var item in items)
                    if (!hs.Add(item))
                        return false;
        
                return true;
            }
        
            public static bool IsEmpty<T>(this IEnumerable<T> items) => !items.Any();
        
            public static IEnumerable<IEnumerable<T>> AllCombinations<T>(this IEnumerable<T> start) {
                IEnumerable<IEnumerable<T>> HelperCombinations(IEnumerable<T> items) {
                    if (items.IsEmpty())
                        yield return items;
                    else {
                        var head = items.First();
                        var tail = items.Skip(1);
                        foreach (var sequence in HelperCombinations(tail)) {
                            yield return sequence; // Without first
                            yield return sequence.Prepend(head);
                        }
                    }
                }
        
                return HelperCombinations(start).Skip(1); // don't return the empty set
            }
        }
        
        var keys = Enumerable.Range(0, src.Count - 1)
                    .SelectMany(n1 => Enumerable.Range(n1 + 1, src.Count - n1 - 1).Select(n2 => new { n1, n2 }))
                    .Select(n1n2 => new { s1 = src[n1n2.n1], s2 = src[n1n2.n2], Dist = src[n1n2.n1].TakeWhile((ch, n) => n < src[n1n2.n2].Length && ch == src[n1n2.n2][n]).Count() })
                    .SelectMany(s1s2d => new[] { new { s = s1s2d.s1, s1s2d.Dist }, new { s = s1s2d.s2, s1s2d.Dist } })
                    .Where(sd => sd.Dist > 0)
                    .GroupBy(sd => sd.s.Substring(0, sd.Dist))
                    .Select(sdg => sdg.Distinct())
                    .AllCombinations()
                    .Where(sdgc => sdgc.Sum(sdg => sdg.Count()) == src.Count)
                    .Where(sdgc => sdgc.SelectMany(sdg => sdg.Select(sd => sd.s)).IsDistinct())
                    .OrderByDescending(sdgc => sdgc.Sum(sdg => sdg.First().Dist)).First()
                    .Select(sdg => sdg.First())
                    .Select(sd => sd.s.Substring(0, sd.Dist))
                    .ToList();
        
        var groups = src.GroupBy(s => keys.First(k => s.StartsWith(k)));
        

        【讨论】:

          猜你喜欢
          • 2018-05-07
          • 1970-01-01
          • 2021-02-14
          • 1970-01-01
          • 2011-10-01
          • 2020-11-13
          • 1970-01-01
          • 2020-12-12
          • 2012-01-24
          相关资源
          最近更新 更多