C# 带有公共前缀的字符串的组列表

C# 带有公共前缀的字符串的组列表,c#,string,list,linq,C#,String,List,Linq,假设我有一个字符串列表[city01,city01002,state2,state03,city04,statebg,countryqw,countrypo] 如何在类的词典中对它们进行分组 city - [city01, city04, city01002] state- [state02, state03, statebg] country - [countrywq, countrypo] 如果没有代码,请任何人帮助您接近或继续操作?您可以使用LINQ: var input = new

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

如何在
类的
词典中对它们进行分组

city - [city01, city04, city01002]
state- [state02, state03, statebg]
country - [countrywq, countrypo]
如果没有代码,请任何人帮助您接近或继续操作?

您可以使用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());
var输入=新列表()
{“城市01”、“城市01002”、“州02”,
“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());

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

使用系统;
使用System.Collections.Generic;
使用System.Linq;
公共课程
{
公共静态void Main()
{
List ungroupedList=新列表(){“city01”、“city01002”、“state02”、“state03”、“city04”、“statebg”、“countryqw”、“countrypo”、“第一镇”};
var groupedStrings=ungroupedList.GroupBy(x=>groupingCondition(x));
foreach(groupedStrings中的变量a){
控制台写入线(“键:+a键”);
foreach(a中的var b){
控制台写入线(“值:+b”);
}
}
}
公共静态字符串分组条件(字符串s){
如果(s.StartsWith(“城市”)| s.EndsWith(“城镇”))
回归“城市”;
如果(s.StartsWith(“国家”))
返回“国家”;
如果(s.StartsWith(“州”))
返回“状态”;
返回“未知”;
}
}

我想您在列表中有一个正在搜索的引用列表:

    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)));
    }
var list=新列表()
{“城市01”、“城市01002”、“州02”,
“state03”、“city04”、“statebg”、“countryqw”、“countrypo”};
var tofound=新列表(){“城市”、“州”、“国家”}//已找到对的引用
var result=newdictionary();
foreach(tofound中的var f)
{
添加(f,list.FindAll(x=>x.StartsWith(f));
}

结果,你得到了想要的词典。如果未找到参考键的值,则键的值为null

警告:此答案具有组合扩展,如果原始字符串集较大,则将失败。跑了几个小时后,我放弃了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)));
公共静态类IEnumerableExt{
公共静态布尔值是不可区分的(此IEnumerable items){
var hs=新的HashSet();
foreach(项目中的var项目)
如果(!hs.添加(项目))
返回false;
返回true;
}
公共静态bool为空(此IEnumerable items)=>!items.Any();
公共静态IEnumerable所有组合(此IEnumerable开始){
IEnumerable Helper组合(IEnumerable项){
if(items.IsEmpty())
收益回报项目;
否则{
var head=items.First();
var tail=项目。跳过(1);
foreach(HelperCombinations中的var序列(tail)){
产生返回序列;//不带第一个
收益率返回序列。预结束(头);
}
}
}
return HelperCombinations(start).Skip(1);//不返回空集
}
}
var keys=Enumerable.Range(0,src.Count-1)
.SelectMany(n1=>Enumerable.Range(n1+1,src.Count-n1-1)。选择(n2=>new{n1,n2}))
.Select(n1n2=>new{s1=src[n1n2.n1],s2=src[n1n2.n2],Dist=src[n1n2.n1].TakeWhile((ch,n)=>nnew[]{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())
.所有组合()
.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));

为什么你认为第一组不会是城市0
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)));