c# - 如何根据键值组将字典拆分为多个字典?
问题描述
我有一本Dictionary<string, string>
包含一组 KeyValuePairs KVP 的字典。
出于本说明的目的,这些存储在字典中。_test
这些打算用于 SQL INSERT usingcommand.Parameters.AddWithValue(value.key, value.Value)
但是,这会将所有值插入到 SQL 的一行中,其中预期的结果是多行。
示例来源_test
;
[0] {[Data, ONCE,UPON,A,TIME,UP,AN,ENORMOUS,GREEN,BEANSTALK,IN,THE,CLOUDS]}
[1] {[Ident, 123456789]}
[2] {[Time1, 2020-01-01T13:56:56.123]}
[3] {[Time2, 2020-01-01T13:58:02.356]}
[4] {[D, 57]}
[5] {[D1, 508,967,123,456,234,456,232,124,167,198,985,786]}
[6] {[AC, 1,1,1,1,2,2,2,4,3,3,1,1]}
我希望将这些值根据出现在键 AC 下的值分组拆分为多个字典,因此输出将是;
然后我可以使用foreach
interate 每个字典来执行每个插入。
dict-1
(包含基于 AC 为 1 的前 4 个值)
dictionary<string,string>
[0] {[Data, ONCE,UPON,A,TIME]}
[1] {[Ident, 123456789]}
[2] {[Time1, 2020-01-01T13:56:56.123]}
[3] {[Time2, 2020-01-01T13:58:02.356]}
[4] {[D, 57]}
[5] {[D1, 508,967,123,456]}
[6] {[AC, 1,1,1,1]}
dict-2
(包含基于 AC 值为 2 的下 3 个值)
dictionary<string,string>
[0] {[Data, UP,AN,ENORMOUS]}
[1] {[Ident, 123456789]}
[2] {[Time1, 2020-01-01T13:56:56.123]}
[3] {[Time2, 2020-01-01T13:58:02.356]}
[4] {[D, 57]}
[5] {[D1, 234,456,232]}
[6] {[AC, 2,2,2]}
dict-3
(包含基于 AC 4 的单个值)
dictionary<string,string>
[0] {[Data, GREEN]}
[1] {[Ident, 123456789]}
[2] {[Time1, 2020-01-01T13:56:56.123]}
[3] {[Time2, 2020-01-01T13:58:02.356]}
[4] {[D, 57]}
[5] {[D1, 124]}
[6] {[AC, 4]}
dict-4
dictionary<string,string>
[0] {[Data, BEANSTALK,IN]}
[1] {[Ident, 123456789]}
[2] {[Time1, 2020-01-01T13:56:56.123]}
[3] {[Time2, 2020-01-01T13:58:02.356]}
[4] {[D, 57]}
[5] {[D1, 167,198]}
[6] {[AC, 3,3]}
dict-5
dictionary<string,string>
[0] {[Data, THE,CLOUDS]}
[1] {[Ident, 123456789]}
[2] {[Time1, 2020-01-01T13:56:56.123]}
[3] {[Time2, 2020-01-01T13:58:02.356]}
[4] {[D, 57]}
[5] {[D1, 985,786]}
[6] {[AC, 1,1]}
他们是使用 Linq 方法或查询语法做这件事的好方法吗?
解决方案
使用我已经使用的一些扩展方法来处理IEnumerable
s,包括用于运行的 group by 运算符、APL Scan 运算符以及此处看到的一些基本实用程序方法:
public static class IEnumerableExt {
// returns IEnumerables of runs
public static IEnumerable<IEnumerable<T>> Runs<T>(this IEnumerable<T> items) {
var cmp = EqualityComparer<T>.Default;
using (var itemsEnum = items.GetEnumerator()) {
bool notAtEnd;
IEnumerable<T> NextRun() {
T curItem;
do {
curItem = itemsEnum.Current;
yield return curItem;
notAtEnd = itemsEnum.MoveNext();
} while (notAtEnd && cmp.Equals(itemsEnum.Current, curItem));
}
notAtEnd = itemsEnum.MoveNext();
while (notAtEnd)
yield return NextRun().ToList();
}
}
// APL Scan operator (like Aggregate, but returns intermediate results)
// T combineFn(T PrevResult, T CurItem)
// First PrevResult = items.First()
// First CurItem = items.Skip(1).First()
// output is items.First(), combineFn(PrevResult, CurItem), ...
public static IEnumerable<T> Scan<T>(this IEnumerable<T> items, Func<T, T, T> combineFn) {
using (var itemsEnum = items.GetEnumerator()) {
if (itemsEnum.MoveNext()) {
T prevResult = itemsEnum.Current;
for (; ; ) {
yield return prevResult;
if (!itemsEnum.MoveNext())
yield break;
prevResult = combineFn(prevResult, itemsEnum.Current);
}
}
}
}
// prepend a sequence with a single element
public static IEnumerable<T> FollowedBy<T>(this T first, IEnumerable<T> rest) => first.AsSingleton().Concat(rest);
// Join strings together with a separator
public static string Join(this IEnumerable<string> s, string sep) => String.Join(sep, s);
// convert an element into a single element IEnumerable
public static IEnumerable<T> AsSingleton<T>(this T item) => new[] { item };
}
您可以创建要拆分的每个组合值的起始位置序列,然后创建表示要为每个可拆分键值收集的值的范围序列。
我使用了一个变量来指定可拆分的键名,以防它们将来可能发生变化,并且只是复制了所有不可拆分的键名/值对。
var splitKeyNames = new[] { "Data", "D1", "AC" };
var splitValues = splitKeyNames.ToDictionary(n => n, n => _test[n].Split(','));
var starts = splitValues["AC"].Runs()
.Select(run => run.Count())
.Scan((acc, runCt) => acc + runCt);
var ranges = 0.FollowedBy(starts).Zip(starts, (start, end) => start .. end);
var ans = ranges.Select(range => _test.Keys.Where(key => !splitKeyNames.Contains(key))
.Select(key => new { key, value = _test[key] })
.Concat(
splitKeyNames.Select(key => new {
key,
value = splitValues[key][range].Join(",")
}))
.ToDictionary(kv => kv.key, kv => kv.value)
);
推荐阅读
- spring - 如何使用 Spring 数据 mongodb 将字段数组添加到 ProjectionOperation
- ethereum - 如何在松露控制台中调用别人的合同?
- sass - 获取 SCSS 中的当前属性值引用
- javascript - 如何将chart.js图表选项存储在AngularJS的另一个文件中
- xslt-2.0 - 如何检查输入的长度是否等于 10
- php - 为什么调用函数后变量值没有改变
- apache-spark - 当我们在纱线集群中运行时,我们在哪里可以看到火花输出控制台
- ms-access - 如何创建在特定日期之后删除条目的 Access 数据库
- angular - (Angular) Ng build 没有创建更新的项目
- jquery - 我将如何使用 Jquery 将乘数添加到预定义的数字?