我正在尝试从字典中的键下面的单个集合创建字典集合,每个类型为“k”的文件,每个键的值都是“a”类型的文件。换句话说,我正在尝试建立父子关系,但文件名是唯一的,并不表示“a”和“k”文件类型之间的关系。唯一的关系是文件日期。例如,文件4将是一个密钥b / c它的类型为“k”,它的值将是文件3和2,因为它们的文件日期大于文件3的日期。文件1不应作为文件4的子文件包含在内,因为它的类型为“k”,即使它的日期大于文件3。
使用单一集合:
IEnumerable<IFile>
file name file type file date
file1 k 2013-01-01
file2 a 2012-03-30
file3 a 2012-02-27
file4 k 2012-02-23
file5 a 2011-03-31
file6 k 2011-02-24
file7 a 2010-08-24
file8 a 2010-03-31
file9 k 2010-02-26
期望的输出:
Dictionary<IFile, IEnumerable<IFile>>
key value
file1 none b/c no files of type "a" exist with a date greater than file1
file4 file3, file2
file6 file5
file9 file8, file7
答案 0 :(得分:0)
您可以执行以下操作:
var result = data.Where(x => x.Type == 'k')
.ToDictionary(x => x.Name,
x => data.Where(a => a.Type == 'a' &&
a.Date >= x.Date)
.Select(a => a.Name)
.ToList());
这不会完全得到你想要的东西 - 因为2010-02-26的条目将包括未来的所有。所以这不仅仅是这种关系的一个例子:
例如,文件4将是一个键盘b / c它的类型为“k”,它的值将是文件3和2,因为它们的文件日期大于文件3的日期。
听起来确实如此:
例如,文件4将是一个密钥b / c它的类型为“k”,它的值将是文件3和2,因为它们的文件日期大于文件3的日期,并且它们的文件日期小于档案1的日期。
那会更棘手。您可能需要以下内容:
var orderedKeys = data.Where(x => x.Type == 'k')
.OrderBy(x => x.Date)
.Concat(null); // You'll see why in a minute...
// Just for convenience. Could make this more efficient, admittedly.
var values = data.Where(x => x.Type == 'a').ToList();
var result = orderedKeys.Zip(orderedKeys.Skip(1),
(current, next) => new { current, next })
.ToDictionary(pair => pair.current.Name,
// Sorry for the formatting...
pair => values.Where(v => v.Date >= pair.current.Date &&
pair.next == null || v.Date < pair.next.Date)
.Select(v => v.Name)
.ToList());
如果你想真的 LINQ-y那就是。按日期排序键和值排序会更有效:
var ordered = data.OrderBy(x => x.Date);
var result = new Dictionary<string, List<string>>();
var currentList = null;
foreach (var item in ordered)
{
if (item.Type == 'a' && currentList != null)
{
currentList.Add(item.Name);
}
else if (item.Type == 'k')
{
currentList = new List<string>();
result[item.Name] = currentList;
}
}
答案 1 :(得分:0)
这是一个相当简单的基于LINQ的解决方案(非常简洁,没有我的所有评论):
// first, get the key files in order by date
var orderedKeys = files.Where(f => f.Type == 'k')
.OrderBy(f => f.Date)
// since I'm going to be enumerating this multiple times, call ToList() so we only
// do the sort and filter once (if you don't care you could just inline this below)
.ToList();
// start with all files of type 'a'
var dict = files.Where(f => f.Type == 'a')
// group the 'a' files by the last key file whose date is <= the date of the 'a'
// file. Since we've sorted the key files, this should be the correct parent for a
.GroupBy(f => orderedKeys.Where(key => key.Type == 'k').Last(key => key.Date <= f.Date))
// finally, convert the groups to a Dictionary
.ToDictionary(g => g.Key, g => g);
请注意,这有点效率低,因为它循环遍历每个'a'文件可枚举的orderedKeys(尽管文件列表不是太大,但简洁性可能是值得的)。为避免这种情况,您可以使用非LINQ迭代解决方案,首先对整个文件列表进行排序。
答案 2 :(得分:0)
您可以使用this answer中的Split
扩展程序获取每个密钥的项目。然后,您可以Zip
包含项目的键,并将序列转换为Dictionary
。
var orderedFiles = files.OrderBy(f => f.Date).ToArray();
var keys = orderedFiles.Where(f => f.Type == 'k');
// Call Skip(1) to skip the items that are before any keys.
var itemGroups = orderedFiles.Split(f => f.Type == 'k').Skip(1);
var result = keys.Zip(itemGroups, (key, items) => new { key, items })
.ToDictionary(x => x.key, x => x.items);
这是扩展方法:
public static IEnumerable<IEnumerable<TSource>> Split<TSource>(
this IEnumerable<TSource> source,
Func<TSource, bool> predicate)
{
List<TSource> group = new List<TSource>();
foreach (TSource item in source)
{
if (predicate(item))
{
yield return group.AsEnumerable();
group = new List<TSource>();
}
else
{
group.Add(item);
}
}
yield return group.AsEnumerable();
}