过于简化,人为的问题
我有一个可枚举的实例,它可以包含一系列连续的元素,以及与它们交叉分散的一些其他元素。一个简单的例子
var items = new[]
{"1","1","1","1","1","varX","1","1","1","1","varY","1","1"};
正如您所看到的,字符串1
会重复,然后不时地出现其他内容(非常容易识别)。让我们说我想以一种形成可枚举的方式进行聚合
var aggregated = new[]
{ "11111", "varX", "1111", "varY","11"};
这显然只是“所有1的连接”后跟“var”后跟下一组1连接。等
不要太乱挂字符串细节;将“1”视为对象Word
和“var”的实例,将其视为对象Variable
的实例。现在我想将Word
连接在一起(做一个句子)并以不同的方式处理Variable
我如何使用LINQ编写聚合,或者仅仅使用简单的foreach?
略有简化,同样的问题
我有一个“令牌”的可列表。只有两种类型的令牌,都来自基本令牌:
public abstract class Token{}
public class WordToken : Token {}
public class VariableToken : Token {}
字符串:
Hello world {varX}你是怎么{varY}再见
我的代码将对以下可枚举的
进行标记 var tokens = new[]
{
WordToken,
WordToken,
VariableToken,
WordToken,
WordToken,
WordToken,
VariableToken,
WordToken
};
我希望将其转为
var newList = new []
{
FragmentToken,
VariableToken,
FragmentToken,
VariableToken,
FragmentToken
};
FragmentToken
所有单词串联起来的地方
显而易见的第一步是聚合原始列表以制作
var step = new[]
{
new[]{WordToken, WordToken},
new[]{VariableToken},
new[]{ WordToken, WordToken, WordToken},
new[]{VariableToken},
new[]{WordToken}
};
然后我可以轻松地完成下一步,但我无法理解如何进入第一步。
答案 0 :(得分:3)
这是否接近您想要的解决方案?
public abstract class Token : IComparable
{
public int CompareTo(object obj)
{
if (obj == null)
{
return -1;
}
return GetType().FullName.CompareTo(obj.GetType().FullName);
}
}
public class WordToken : Token { }
public class VariableToken : Token { }
public static class ListExtensions
{
public static IEnumerable<IEnumerable<TEntity>> JoinRepeatedValues<TEntity>(this IEnumerable<TEntity> collection)
where TEntity : IComparable
{
var joinedRepeatedValuesCollection = new List<List<TEntity>>();
var lastValue = default(TEntity);
foreach (var item in collection)
{
if (item.CompareTo(lastValue) != 0)
{
joinedRepeatedValuesCollection.Add(new List<TEntity> { item });
}
else
{
var lastAddedValue = joinedRepeatedValuesCollection.Last();
lastAddedValue.Add(item);
}
lastValue = item;
}
return joinedRepeatedValuesCollection;
}
}
class Program
{
static void Main(string[] args)
{
var tokens = new Token[]
{
new WordToken(),
new WordToken(),
new VariableToken(),
new WordToken(),
new WordToken(),
new WordToken(),
new VariableToken(),
new WordToken()
};
var joinedValues = tokens.JoinRepeatedValues();
var items = new[] { "1", "1", "1", "1", "1", "varX", "1", "1", "1", "1", "varY", "1", "1" }.JoinRepeatedValues();
}
}
答案 1 :(得分:2)
嗯,基于我对问题的理解,这是一次尝试
var initialList;//whatever this contains...
List<List<Object>> retList = new List<List<Object>>();
Type storedType = null;
foreach(Object thing in initialList)
{//we treat this like a simple array of objects, because we DONT know what's in it.
if(storedType != null)
{
if(storedType.Equals(thing.GetType())
instanceList.Add(thing);
else
{//add instanceList to the master return, then re-set stored type and the
//list and add the current thing to the new list
retList.Add(instanceList);
storedType = thing.GetType();
instanceList = new List<Object>();
instanceList.Add(thing);
}
}
else
{//should be First run only
storedType = thing.GetType();
instanceList.Add(thing);
}
}
return retList;
添加了备注:
如果所有对象都应该是相同的Type
,那么不是检查类型,而是检查并存储该值,但基本算法保持不变。此外,您可以使用内容的确切类型而不是Object
,如果您正在检查值,这是非常必要的。
===========================================
在保持当前项目顺序的同时,不知道如何使用linq执行此操作。如果这不重要,Linq的OfType<>
方法将成为可行的方法,根据类型过滤列表。不幸的是,你不能在类型规范中使用变量,所以你需要提前知道可能在initialList中的所有类型的严格列表。