1

ディクショナリのキーの下にある単一のコレクションからディクショナリ コレクションを作成しようとしていますが、各キーの値はタイプ「a」のファイルです。つまり、親子関係を構築しようとしていますが、ファイル名は一意であり、「a」と「k」のファイル タイプの関係を示していません。唯一の関係はファイルの日付です。たとえば、ファイル 4 はキー b/c で、タイプは "k" であり、ファイルの日付がファイル 3 の日付よりも大きいため、その値はファイル 3 と 2 になります。ファイル 1 はファイル 4 の子として含めるべきではありません。これは、日付がファイル 3 よりも大きい場合でも、ファイル 4 のタイプが「k」であるためです。

使用する単一のコレクション:

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
4

3 に答える 3

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はタイプ「k」のキーb / cになり、ファイルの日付がファイル3の日付よりも大きいため、値はファイル3と2になります。

実際には次のように聞こえます。

たとえば、ファイル4はタイプ「k」のキーb / cになり、ファイルの日付はファイル3の日付より大きく、ファイルの日付はファイル1の日付よりも小さいため、値はファイル3と2になります。

それは難しいでしょう。次のようなものが必要になる場合があります。

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;
    }
}
于 2012-09-22T06:56:59.223 に答える
0

この回答Splitの拡張メソッドを使用して、各キーのアイテムを取得できます。次に、キーをアイテムに使用し、シーケンスを.ZipDictionary

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();
}
于 2012-09-22T16:38:11.960 に答える
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 反復ソリューションを使用できます。

于 2012-09-22T14:21:49.477 に答える