C# 按关键字列表拆分字符串列表

C# 按关键字列表拆分字符串列表,c#,list,linq,C#,List,Linq,我有一个字符串列表 e、 g.{“apple.txt”、“orange.sd.2.txt”、“apple.2.tf.txt”、“orange.txt”} 和另一个字符串列表来对第一个列表进行分组 e、 g.{“苹果”、“橘子”} 因此,第一个列表被拆分为一个列表列表,如下所示: {{“apple.txt”、“apple.2.tf.txt”}、{“orange.txt”、“orange.sd.2.txt”} 我怎样才能用linq实现这一点呢?元组拯救 var R = new List<(st

我有一个字符串列表 e、 g.{“apple.txt”、“orange.sd.2.txt”、“apple.2.tf.txt”、“orange.txt”} 和另一个字符串列表来对第一个列表进行分组 e、 g.{“苹果”、“橘子”} 因此,第一个列表被拆分为一个列表列表,如下所示:

{{“apple.txt”、“apple.2.tf.txt”}、{“orange.txt”、“orange.sd.2.txt”}

我怎样才能用linq实现这一点呢?

元组拯救

var R = new List<(string, List<string>)> { ("orange", new List<string>()), ("apple", new List<string>()) };
var L = new List<string> { "apple.txt", "apple.2.tf.txt", "orange.txt", "orange.sd.2.txt" };
R.ForEach(r => L.ForEach(l => { if (l.Contains(r.Item1)) { r.Item2.Add(l); } }));
var resultString = string.Join("," , R.Select(x => "{" + string.Join(",", x.Item2) + "}"));
var R=newlist{(“橙色”,newlist()),(“苹果”,newlist())};
var L=新列表{“apple.txt”、“apple.2.tf.txt”、“orange.txt”、“orange.sd.2.txt”};
R.ForEach(R=>L.ForEach(L=>{if(L.Contains(R.Item1)){R.Item2.Add(L);}}});
var resultString=string.Join(“,”,R.Select(x=>“{”+string.Join(“,”,x.Item2)+“}”);
如果需要,您可以轻松地动态构建R。

这样如何:

var groupedList = firstList.GroupBy(x => secondList.Single(y => x.Name.Contains(y)));

您可以使用
Split
SelectMany
GroupBy
以匿名类型按所有可能的键对每个原始
列表的元素进行分组:

var list = new List<string> { "apple.txt", "orange.sd.2.txt", "apple.2.tf.txt", "orange.txt" };
var groups = list
    .SelectMany(element => element
        .Split('.')
        .Select(part => new { Part = part, Full = element }))
    .GroupBy(entry => entry.Part);
注意:原始列表中不包含任何指定键的元素将不会出现在结果中,并且包含多个指定键的元素将在结果中出现多次

编辑:正如@NetMage所指出的,我对拆分字符串做了一个错误的假设-这里是另一个版本,尽管它是
O(m*n)


这是一个简单的方法。有很多方法,这将包括重复键作为我对你的问题的评论。如果多个键匹配相同的数据,分组将包括副本

// have the list of keys (groups)
var keyList = new List<string>() {"apple", "orange"};

// have the list of all the data to split
var dataToSplit = new List<string>() 
{
    "apple.txt", 
    "apple.2.tf.txt",
    "orange.txt", 
    "orange.sd.2.txt"
};

// now split to get just as desired you select what you want for each keys
var groupedData = keyList.Select(key => dataToSplit.Where(data => data.Contains(key)).ToList()).ToList();

// groupedData is a List<List<string>>
现在,使用该扩展,当您有一个列表时,您可以像这样轻松地使用它:

// have the list of keys (groups)
var keyList = new List<string>() {"apple", "orange"};

// have the list of all the data to split
var dataToSplit = new List<string>() 
{
    "apple.txt", 
    "apple.2.tf.txt",
    "orange.txt", 
    "orange.sd.2.txt"
};

// now split to get just as desired you select what you want for each keys
var groupedData = keyList.Select(key => dataToSplit.RemoveAndGet(data => data.Contains(key))).ToList();
//拥有密钥列表(组)
var keyList=new List(){“apple”,“orange”};
//有要拆分的所有数据的列表
var dataToSplit=新列表()
{
“apple.txt”,
“apple.2.tf.txt”,
“orange.txt”,
“orange.sd.2.txt”
};
//现在拆分以获得所需的内容,您可以为每个关键点选择所需的内容
var groupedData=keyList.Select(key=>dataToSplit.RemoveAndGet(data=>data.Contains(key)).ToList();

在这种情况下,由于两个集合中的顺序,第一个键是
apple
,因此它将迭代
dataToSplit
中的4项,并仅保留2项,并将
dataToSplit
集合减少为2项,其中只有
orange
。在第二个键上,它将只迭代2个项目,这将使它在这种情况下更快。通常,此方法将与我提供的前两种方法一样快或更快,同时保持清晰,并且仍然使用linq。

您可以使用以下简单代码实现此目的:

var list1 = new List<string>() {"apple.txt", "orange.sd.2.txt", "apple.2.tf.txt", "orange.txt"};
var list2 = new List<string>() {"apple", "orange"};
var result = new List<List<string>>();

list2.ForEach(e => {
    result.Add(list1.Where(el => el.Contains(e)).ToList());
});
var list1=new List(){“apple.txt”、“orange.sd.2.txt”、“apple.2.tf.txt”、“orange.txt”};
var list2=新列表(){“苹果”、“橙色”};
var result=新列表();
清单2.ForEach(e=>{
Add(list1.Where(el=>el.Contains(e)).ToList());
});

如果字符串名为“apple.orange.txt”它必须如何运行?它不是一个用例,但可以在两个组中。最终列表的顺序是否需要与分组列表中的顺序相匹配?这是否意味着要作为您问题的答案或扩展?您可能希望首先使用
,除非您确定给定的组不能有多个键匹配
firstList
成员。除非您确定每个
firstList
成员都属于一个组,否则您可能希望使用
FirstOrDefault
。否则,做得很好。您可以使用
SelectMany
进行更多的处理,将其转换为处理属于多个组的项:
dataToSplit.SelectMany(ds=>keyList.Where(k=>ds.Contains(k)).Select(k=>new{Key=k,Value=ds})).GroupBy(kds=>kds.Key,kds=>kds.Value)
@GertArnold我猜一个可能的答案“这个怎么样:”是一个新问题。有趣的方法-通过将
转换为
哈希集
我认为这最接近O(n)解决方案,虽然我相信处理所有不需要的部分的开销以及在
上拆分是可行的假设意味着这不是最好的答案。@NetMage谢谢,你是对的,这是一个不正确的假设-在我的回答中添加了替代方案我试图想办法避免O(m*n)并使其成为O(n),但我看不到,如果你把一个有2个键的物品归为2类,除了O(m*n)之外,你不能做任何其他的事情。如果你不在乎,这些案例可能属于随机案例,那么就有可能降低复杂性。您需要的是迭代数据集合,并在找到匹配项时从该集合中删除,这将在构建列表时减少后续键的数据子集。有趣的是,我的迭代是在数据之上,然后是在键之上,假设数据更长,因此,如果您只需要包含的第一个键,您可以停止早期搜索键。
// have the list of keys (groups)
var keyList = new List<string>() {"apple", "orange"};

// have the list of all the data to split
var dataToSplit = new List<string>() 
{
    "apple.txt", 
    "apple.2.tf.txt",
    "orange.txt", 
    "orange.sd.2.txt"
};

// create the anonymous
var anonymousGroup = keyList.Select(key =>
{
    return new 
    { 
        Key = key, 
        Data = dataToSplit.Where(data => data.Contains(key)).ToList()
    }
});

// anonymousGroup is a List<A> where keeping the order you should access all data for orange like this
var orangeGroup = anonymousGroup.FirstOfDefault(o=> o.Key = "orange"); // get the anonymous
var orangeData = orangeGroup.Data; // get the List<string> for that group
public static List<T> RemoveAndGet<T>(this List<T> list, Func<T, bool> predicate)
{
    var itemsRemoved = new List<T>();

    // iterate backward for performance
    for (int i = list.Count - 1; i >= 0; i--)
    {
        // keep item pointer
        var item = list[i];

        // if the item match the remove predicate
        if (predicate(item))
        {
            // add the item to the returned list
            itemsRemoved.Add(item);

            // remove the item from the source list
            list.RemoveAt(i);
        }
    }

    return itemsRemoved;
}
// have the list of keys (groups)
var keyList = new List<string>() {"apple", "orange"};

// have the list of all the data to split
var dataToSplit = new List<string>() 
{
    "apple.txt", 
    "apple.2.tf.txt",
    "orange.txt", 
    "orange.sd.2.txt"
};

// now split to get just as desired you select what you want for each keys
var groupedData = keyList.Select(key => dataToSplit.RemoveAndGet(data => data.Contains(key))).ToList();
var list1 = new List<string>() {"apple.txt", "orange.sd.2.txt", "apple.2.tf.txt", "orange.txt"};
var list2 = new List<string>() {"apple", "orange"};
var result = new List<List<string>>();

list2.ForEach(e => {
    result.Add(list1.Where(el => el.Contains(e)).ToList());
});