1
string[] filesOfType1 = GetFileList1();
string[] filesOfType2 = GetFileList2();
var cookieMap = new Dictionary<string, CookieContainer>();

Action<string, Func<string, KeyValuePair<string, CookieContainer>>> addToMap = (filename, pairGetter) =>
    {
        KeyValuePair<string, CookieContainer> cookiePair;
        try
        {
            cookiePair = pairGetter(filename);
        }
        catch
        {
            Console.WriteLine("An error was encountered while trying to read " + file + ".");
            return;
        }

        if (cookieMap.ContainsKey(cookiePair.Key))
        {
            if (cookiePair.Value.Count > cookieMap[cookiePair.Key].Count)
            {
                cookieMap[cookiePair.Key] = cookiePair.Value;
            }
        }
        else
        {
            cookieMap.Add(cookiePair.Key, cookiePair.Value);
        }
    };


foreach (string file in filesOfType1)
{
    addToMap(file, GetType1FileCookiePair);
}
foreach (string file in filesOfType2)
{
    addToMap(file, GetType2FileCookiePair);
}

維持しなければならない顕著な特徴:

  • タイプ 1 のファイルは、タイプ 2 のファイルよりも重要です。つまり、タイプ 1 のファイルが (キー、値 1) の組み合わせにマップされ、タイプ 2 のファイルが (キー、値 2) の組み合わせにマップされる場合、(キー、値 2) ではなく(キー、値 1)を cookieMap に追加します。編集:Bevanが指摘したように、これは私の元の手続き型コードでは満足できません。
  • 次に、が高いCookieContainersCountほど優先度が高くなります。つまり、同じキーに対して 2 つの (キー、値) コンボがあり、両方とも同じファイルタイプからのものである場合、 が高い方を選択しますvalue.Count
  • ケースごとの例外処理は必須です。単一のファイル読み取りを台無しにするだけで、それに注意して続行できるようになります。

私の最善の試みは次のように始まりました:

var cookieMap = (filesOfType1.Select(file => GetType1FileCookiePair(file))
                .Concat(filesOfType2.Select(file => GetType2FileCookiePair(file))))
                    .GroupBy(pair => pair.Key)
                    .Select(/* some way of selecting per the above bullets */)
                    .ToDictionary(pair => pair.Key, pair => pair.Value);

しかし、それは洗練されておらず、そのコメント ブロックに記入するのは雌犬のように思えます。今のところ、私は手続き型にとどまることに満足していますが、人々が本当に賢い何かを思いつくことができるかどうかを見るのは楽しい挑戦かもしれないと思いました.

4

3 に答える 3

3

これが私の試みです-タスクを3つの異なるステートメントに分割するのが最も簡単に思えました。

アクションが例外をスローした場合に null を返すヘルパー関数を使用しています - Omer van Kloeten からの回答と一貫性を保つために、これを Swallow() と呼びました

また、LINQ 構文は使用していません。System.Linq.Enumerable によって提供される拡張メソッドのみを使用しています。

最後に、これはコンパイルされていないことに注意してください。

// Handle all files of type 1
var pairsOfType1 = 
    filesOfType1
        .Select( file => Swallow( pairGetter(file)))
        .Where( pair => pair != null);

// Handle files of type 2 and filter out those with keys already provided by type 1
var pairsOfType2 =
    filesOfType2
        .Select( file => Swallow( pairGetter(file)))
        .Where( pair => pair != null);
        .Where( pair => !pairsOfType1.Contains(p => p.Key == pair.Key));

// Merge the two sets, keeping only the pairs with the highest count
var cookies =
    pairsOfType1
        .Union( pairsOfType2)
        .GroupBy( pair => pair.Key)
        .Select( group => group.OrderBy( pair => pair.Value.Count).Last());
        .ToDictionary( pair => pair.Key);
于 2008-10-27T08:25:17.277 に答える
2
using CookiePair = KeyValuePair<string, CookieContainer>;
using CookieDictionary = Dictionary<string, CookieContainer>;

Func<string[], Func<string, CookiePair>, IEnumerable<CookiePair>> getCookies =
  ( files, pairGetter ) =>
    files.SelectMany( filename => {
      try { return new[] { pairGetter( filename ) }; }
      catch { Console.WriteLine( "..." ); return new CookiePair[0]; }
    } );

var type1Cookies = getCookies( filesOfType1, GetType1FileCookiePair ).ToArray( );
var type1CookieNames = type1Cookies.Select( p => p.Key ).ToArray( );
var type2Cookies = getCookies( filesOfType2, GetType2FileCookiePair )
  .Where( p => !type1CookieNames.Contains( p.Key ) );

var cookieMap = type1Cookies.Concat( type2Cookies )
  .Aggregate( new CookieDictionary( ), ( d, p ) => {
    if( !d.ContainsKey( p.Key ) || p.Value.Count > d[p.Key].Count )
      d[p.Key] = p.Value;
    return d;
  } );

編集:「タイプ 1 のファイルはタイプ 2 のファイルよりも重要である」という要件を満たすように、Cookie の取得を更新しました。

于 2008-10-27T00:38:52.273 に答える
1

申し訳ありませんが、実際に先に進んでこれをコンパイルしていませんが、これは私がそれを行う方法です。

var cookieMap = (from pair in
                     (from f1 in filesOfType1
                      select Swallow(() => GetType1FileCookiePair(f1)))
                         .Concat(from f2 in filesOfType2
                                 select Swallow(() => GetType2FileCookiePair(f2)))
                         .SelectMany(dict => dict)
                 group pair by pair.Key into g
                 select g)
                .ToDictionary(g => g.Key, g => g.Select(pair => pair.Value)
                                                .OrderByDescending(value => value.Count)
                                                .First());

Swallow次のとおりです。

private static T Swallow<T>(Func<T> getT)
{
    try { return getT(); } catch { }

    return default(T);
}

良いLINQを愛してください。

  • 編集:Swallowすべての例外を飲み込むメソッドを追加しました。
  • 編集2:コンパイル、変更など。追加Swallow。意図したとおりに動作するようになりました。
于 2008-10-26T22:36:24.613 に答える