score:5
Not too difficult to do. In your FileList class create a child class that inherits from IEqualityComparer<>
public class FileListComparer : IEqualityComparer<FileList>
{
public bool Equals(FileList x, FileList y)
{
if (x == null || y == null)
{
return false;
}
return x.FileNames.Equals(y.FileNames, StringComparison.OrdinalIgnoreCase);
}
public int GetHashCode(FileList obj) { return base.GetHashCode(); }
}
And then when you call Except, use the Comparer
IEnumerable<FileList> except = sourceFileNames.Except(destinationFileNames, new FileList.FileListComparer() );
score:8
Sourcefilenamelist.Except(Destinaitonlist)
score:14
That's what Except
is for:
var files = sourceFilenameList.Except(destinationList);
Note that this is a set operation, so if the source list has duplicate entries you'll only see unique results: new[] {a, a, b, b, c}.Except(new[] {b, c})
is just {a}
, not {a, a}
.
Like many LINQ operators, this returns an IEnumerable<T>
- if you want it back as a List
just call ToList
:
var files = sourceFilenameList.Except(destinationList).ToList();
EDIT: Okay, now you've shown what FileList
is, the problem is simply that you haven't implemented equality comparisons. You can do this either by overriding Equals
and GetHashCode
(and possibly IEquatable<FileList>
) or by implementing IEqualityComparer<T>
. However, you've still got a problem: FileNames
is a mutable type, and those don't typically work well in terms of hashing and equality. Two instances may be equal initially, and then one of them could change. I'd recommend reimplementing this as an immutable type. Something like this:
public sealed class FileList : IEquatable<FileList>
{
private readonly string fileNames;
public string FileNames { get { return fileNames; } }
public FileList(string fileNames)
{
// If you want to allow a null FileNames, you'll need to change
// the code in a few places
if (fileNames == null)
{
throw new ArgumentNullException("fileNames");
}
this.fileNames = fileNames;
}
public override int GetHashCode()
{
return fileNames.GetHashCode();
}
public override bool Equals(object other)
{
return Equals(other as FileList);
}
public bool Equals(FileList other)
{
return other != null && other.FileNames == FileNames;
}
}
Your sample code could then become:
List<FileList> sourceFileNames = new List<FileList>
{
new FileList("1.txt"),
new FileList("2.txt"),
new FileList("3.txt"),
new FileList("4.txt")
};
List<FileList> destinationFileNames = new List<FileList>
{
new FileList("1.txt"),
new FileList("2.txt")
};
IEnumerable<FileList> except = sourceFileNames.Except(destinationFileNames);
score:2
I upvoted masenkablast answer, i think the default equality comparer for class instances defaults to class instances' memory address comparison(not the value in class instance itself), so you have to provide your own value equality comparison.
But if you have simple data structure, try to use struct. I tried your code and changed class FileList
to struct FileList
, it works, it only displays 3 and 4
[EDIT] If you want to continue using class without implementing the IEqualityComparer, just implement IEquatable on your class, idea sourced from http://msdn.microsoft.com/en-us/library/bb300779.aspx
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace ExceptList
{
class Program
{
static void Main(string[] args)
{
var sourceFileNames = new List<FileList>();
sourceFileNames.Add(new FileList { FileNames = "1.txt" });
sourceFileNames.Add(new FileList { FileNames = "2.txt" });
sourceFileNames.Add(new FileList { FileNames = "3.txt" });
sourceFileNames.Add(new FileList { FileNames = "4.txt" });
List<FileList> destinationFileNames = new List<FileList>();
destinationFileNames.Add(new FileList { FileNames = "1.txt" });
destinationFileNames.Add(new FileList { FileNames = "2.txt" });
var except = sourceFileNames.Except(destinationFileNames);
// list only 3 and 4
foreach (var f in except)
Console.WriteLine(f.FileNames);
Console.ReadLine();
}
}
class FileList : IEquatable<FileList>
{
public string FileNames { get; set; }
#region IEquatable<FileList> Members
public bool Equals(FileList other)
{
//Check whether the compared object is null.
if (Object.ReferenceEquals(other, null)) return false;
//Check whether the compared object references the same data.
if (Object.ReferenceEquals(this, other)) return true;
return FileNames.Equals(other.FileNames);
}
#endregion
public override int GetHashCode()
{
return FileNames.GetHashCode();
}
}
}
score:0
I think Jon Skeet's answer is the best answer, but your other option is looking directly into the property you want to compare (FileNames)
var destNames = destinationFileNames.Select(destName => destName.FileNames);
IEnumerable<FileList> except = sourceFileNames
.Where(sourceName => !destNames.Contains(sourceName.FileNames));
or (same thing in one expression)
IEnumerable<FileList> except = sourceFileNames
.Where(sourceName => !destinationFileNames
.Select(destNames => destNames.FileNames)
.Contains(sourceName.FileNames));
edit: thanks for the downvote; I tested the code and found a bug. It works now!
Source: stackoverflow.com
Related Articles
- Where Not In OR Except simulation of SQL in LINQ to Objects
- Linq select objects in list where exists IN (A,B,C)
- Linq to Select Parent Objects Where Child Objects Have a Matching Child Object
- LINQ query to perform a projection, skipping or wrapping exceptions where source throws on IEnumerable.GetNext()
- LINQ WHERE method alters source collection
- Where can I view LINQ source code?
- LINQ Source Code Available
- Linq to compare two lists of objects where one object has several lists
- Update all objects except one in a collection using Linq
- Linq with where clause in many-to-many EF Code First object
- C# - Linq optimize code with List and Where clause
- Linq to Objects DateTime Except ignore time
- LINQ query Where ID does not exist as a property in a list of objects
- creating Linq to sqlite dbml from DbLinq source code
- Linq to Objects - Where search within a list
- Linq to Select Parent Objects Where Child Objects Dont contain value
- Query with LINQ where Context matches multiple parameters from a List of Objects
- Using linq to Return list of objects where sum of attribute is the Max() in list of list
- What is the correct way of retrieving a given business object from a list of business objects using LINQ Where vs. Find?
- Why the extension method of where for LINQ in this code would print out a single number while it shouldn't print anything at all?
- Reusable LINQ query except for where clause
- how to write LINQ to objects equivalent code for this code
- source code for LINQ 101 samples
- Compare two list of objects in where clause of LINQ
- LINQ Query to compare two values of an object to a list, where both objects must match
- LINQ where clause using Generic IQueryable source
- Using a Linq query to select objects where any value of a property matches values from a list
- LINQ to Entities Question - All objects where all items in subcollection appear in another collection?
- Preserve input with LINQ expression using Except instead of Where
- LINQ query to create a list of objects where each object contains a list
- IQueryable.ToList method messing up with T-SQL sorting order
- Why does this error occur when using SingleAsync?
- how to convert this T-SQL statment to linq
- Divide array into N chunks
- I have a LINQ statement that is partially query and partially method. How can I do this using one or the other?
- Row_number over (Partition by yyy) in Linq?
- Removing digital Signature tags from an xml file
- LINQ Additional Filter in Select Statement
- Fetch all foreign key records from collection
- How to get a Dictionary<string, List<Object> with LINQ?
- How to get repeated values in LINQ
- (C#) LINQ — Cannot find any result with method .Contains()
- Parsing XML into classes using LINQ in C#
- Linq method equivalent for "Into"
- select clause expression problems
- Improve the LINQ query returning indexes of items meeting a certain condition
- Emebeded Statement can not be a declaration or labled stateme
- Getting XML Items depending on a specific Parent ID LINQ
- Filter Out List with another list using LINQ
- LINQ Optimization for searching a if an object exist in a list within a list