c# - 基于另一个属性连接一个属性的值
问题描述
我有这门课
public enum SubStatus { active, inactive, unset}
public class SubItem
{
public SubStatus Status { get; set; }
public string Value { get; set; }
}
类中的值可能如下所示
List<SubItem> list = new List<SubItem>()
{
new SubItem() { Status = SubStatus.active, Value = "1" },
new SubItem() { Status = SubStatus.active, Value = "2" }, //active again, add "2" to the previous
new SubItem() { Status = SubStatus.inactive, Value = "1" },
new SubItem() { Status = SubStatus.active, Value = "2" },
new SubItem() { Status = SubStatus.unset, Value = "2" },
new SubItem() { Status = SubStatus.unset, Value = "1" }, //unset again, add "1" to the previous
new SubItem() { Status = SubStatus.unset, Value = "1" } //unset again, add "1" to the previous
};
现在我需要将字符串值合并在一起,以防Status
一个项目的 等于Status
前一个项目的。所以在这个例子中,结果应该是这样的
List <SubItem> output = new List<SubItem>()
{
new SubItem() { Status = SubStatus.active, Value = "12" },
new SubItem() { Status = SubStatus.inactive, Value = "1" },
new SubItem() { Status = SubStatus.active, Value = "2" },
new SubItem() { Status = SubStatus.unset, Value = "211" }
};
到目前为止我尝试过的确实有效,但不知何故我认为这种方法是错误的,并且 linq 有更好的方法......
List<SubItem> result = new List<SubItem>();
SubItem temp = list.FirstOrDefault();
if (temp != null)
{
foreach (SubItem item in list.Skip(1))
{
if (temp.Status == item.Status)
{
temp.Value += item.Value;
}
else if (temp.Status != item.Status)
{
result.Add(temp);
temp = item;
}
}
}
result.Add(temp);
解决方案
标准 Linq不提供这样的分组,但我们可以手动实现它:
public static partial class EnumerableExtensions {
public static IEnumerable<T[]> ToBatch<T>(this IEnumerable<T> source,
Func<ICollection<T>, T, bool> addToBatch) {
if (null == source)
throw new ArgumentNullException(nameof(source));
else if (null == addToBatch)
throw new ArgumentNullException(nameof(addToBatch));
List<T> batch = new List<T>();
foreach (T item in source) {
// Shall we start a new batch?
if (batch.Count > 0 && !addToBatch(batch, item)) {
yield return batch.ToArray();
batch.Clear();
}
batch.Add(item);
}
if (batch.Count > 0) // do we have a last batch?
yield return batch.ToArray();
}
}
现在,我们可以使用我们的实现作为
// Test Data
List<SubItem> list = new List<SubItem>() {
new SubItem() { Status = SubStatus.active, Value = "1" },
new SubItem() { Status = SubStatus.active, Value = "2" },
new SubItem() { Status = SubStatus.inactive, Value = "1" },
new SubItem() { Status = SubStatus.active, Value = "2" },
new SubItem() { Status = SubStatus.unset, Value = "2" },
new SubItem() { Status = SubStatus.unset, Value = "1" },
new SubItem() { Status = SubStatus.unset, Value = "1" }
};
...
List<SubItem> result = list
.ToBatch((batch, item) => item.Status == batch.First().Status)
.Select(batch => new SubItem() {
Status = batch.First().Status,
Value = string.Concat(batch.Select(item => item.Value))
})
.ToList();
// Let's have a look
Console.Write(string.Join(Environment.NewLine, result
.Select(item => $"{item.Status,-8} : {item.Value}")));
结果:
active : 12
inactive : 1
active : 2
unset : 211
推荐阅读
- python - Odoo12:strptime 无法识别格式 %p (PM/AM)?
- go - 应用程序设计:中央缓存与私有缓存
- android - 在不同的 Imageviews 上显示不同的文件选择器选择
- java - 如何使用 MongoTemplate 将 Mongo Shell 脚本转换为 Java?
- python - 在大写字母之前和之后查找字符串
- sql-server - 计算两行中两个时间戳之间的持续时间 SQL Server
- cmake - 如何将多个导入的目标合并为一个
- amazon-ecs - 使用 AWS Codepipeline 在 ECS 上的每次部署都会创建一个新版本的任务定义
- c# - 对于每个条目具有多个值的选择列表,如何处理空条目?
- angular - ExpressionChangedAfterItHasBeenCheckedError:将加载器组件与加载器拦截器服务一起使用时