1

私は2つのList<FileInfo>リストを持っています、SourceFilesそしてDestFilesSourceファイル名が含まれているが含まれていないアイテムのリストDest、つまり左結合を返すLINQクエリを作成したいと思います。

私のデータセットSourceFilesは次のとおりです。

folder1\a.txt
folder1\b.txt
folder1\c.txt
folder1\d.txt

DestFilesは:

folder2\a.txt
folder2\b.txt
folder2\c.txt

したがって、クエリはを返す必要があります folder1\d.txt

MSDNの例に従って、LINQ構文を使用してみました。

var queryX = from s in SourceFiles
             join d in DestFiles
             on s.Name equals d.Name
             into SourceJoinDest
             from joinRow in SourceJoinDest.DefaultIfEmpty()
             select new
             {
                 joinRow.FullName
             };

および拡張メソッドの使用:

var query = SourceFiles.GroupJoin(DestFiles,
                                    source => source.Name,
                                    dest => dest.Name,
                                    (source,dest) => new
                                    {
                                        path = source.FullName
                                    }).Select(x => x.path.DefaultIfEmpty())

しかし、これらのいずれも機能しません。LINQ構文バージョンは戻りObject reference not sent to an instance of an object、拡張バージョンは戻りますEnumeration yielded no results.

これらのクエリはFullNameプロパティのセットのみを返し、完全なFileInfoオブジェクトは返さないことに気付きました。FullNameそれぞれを取得してを返すコードがFileInfoあり、クエリ内の各アイテムに対してこれを実行してリストを再構築します。FileInfoしかし、クエリから直接返す方法があれば、それは素晴らしいことです。

4

3 に答える 3

3

Joinここでは理想的なツールではないと思います。基本的にあなたはを探していますExcept。ビルトインにExceptは、ラムダを介してプロパティを指定するためのオーバーロードがありません。独自のを作成する必要がありますIEqualityComparer。ただし、次のように行うことができます。

var excepts = SourceFiles.Where(c => !DestFiles.Any(p => p.Name == c.Name)).ToList();

または、フルパスだけを選択するSelectには、最後に使用できます。

var excepts = SourceFiles.Where(c => !DestFiles.Any(p => p.Name == c.Name))
                         .Select(f => f.FullName).ToList();

すばやく実行するための拡張メソッドを用意することをお勧めしExceptますIntersect

public static IEnumerable<U> Except<R, S, T, U>(this IEnumerable<R> mainList, 
                                                IEnumerable<S> toBeSubtractedList,
                                                Func<R, T> mainListFunction, 
                                                Func<S, T> toBeSubtractedListFunction,
                                                Func<R, U> resultSelector)
{
    return EnumerateToCheck(mainList, toBeSubtractedList, mainListFunction, 
                            toBeSubtractedListFunction, resultSelector, false);
}

static IEnumerable<U> EnumerateToCheck<R, S, T, U>(IEnumerable<R> mainList, 
                                                   IEnumerable<S> secondaryList,
                                                   Func<R, T> mainListFunction, 
                                                   Func<S, T> secondaryListFunction,
                                                   Func<R, U> resultSelector,
                                                   bool ifFound)
{
    foreach (var r in mainList)
    {
        bool found = false;
        foreach (var s in secondaryList)
        {
            if (object.Equals(mainListFunction(r), secondaryListFunction(s)))
            {
                found = true;
                break;
            }
        }

        if (found == ifFound)
            yield return resultSelector(r);
    }

    //or may be just
    //return mainList.Where(r => secondaryList.Any(s => object.Equals(mainListFunction(r), secondaryListFunction(s))) == ifFound)
    //               .Select(r => resultSelector(r));
    //but I like the verbose way.. easier to debug..
}

public static IEnumerable<U> Intersect<R, S, T, U>(this IEnumerable<R> mainList, 
                                                   IEnumerable<S> toIntersectList,
                                                   Func<R, T> mainListFunction,
                                                   Func<S, T> toIntersectListFunction,
                                                   Func<R, U> resultSelector)
{
    return EnumerateToCheck(mainList, toIntersectList, mainListFunction, 
                            toIntersectListFunction, resultSelector, true);
}

今あなたの場合、あなたはただすることができます:

var excepts = SourceFiles.Except(DestFiles, p => p.Name, p => p.Name, p => p.FullName)
                         .ToList();
于 2012-12-26T20:53:19.713 に答える
0

を使用する代わりに、joinこれを処理できる可能性があります.Except()

var enumerable = sourceFiles.Except(destFiles, new FileInfoComparer<FileInfo>((f1, f2)=>f1.Name == f2.Name, f=>f.Name.GetHashCode()));

.Except()IEqualityComparer<T>あなたが自分で書くことができるか、ラムダを取るラッパーを使用することができるを取ります。

    class FileInfoComparer<T> : IEqualityComparer<T>
    {
        public FileInfoComparer(Func<T, T, bool> equals, Func<T, int> getHashCode)
        {
            _equals = equals;
            _getHashCode = getHashCode;
        }

        readonly Func<T, T, bool> _equals;
        public bool Equals(T x, T y)
        {
            return _equals(x, y);
        }

        readonly Func<T, int> _getHashCode;
        public int GetHashCode(T obj)
        {
            return _getHashCode(obj);
        }
    } 

いくつかのサンプルデータを使用して実行すると、次の1つのFileInfoオブジェクトが作成されます。"d.txt"

于 2012-12-26T20:53:30.290 に答える
0

あなたはほとんどそれをしました。ただし、宛先ファイルに結合されていないソースファイルのみを取得する必要があります。

var query = from s in SourceFiles
            join d in DestFiles
                on s.Name equals d.Name into g
            where !g.Any() // empty group!
            select s;
于 2012-12-26T20:55:20.500 に答える