Lambda multiple conditions to validate list in list of object? - c#

I have a list composed of the following items
List<person> lst = new List<person>()
lst.Add(new person(){ name="abc", age="24" });
lst.Add(new person(){ name="xyz", age="25" });
lst.Add(new person(){ name="zxc", age="28" });
lst.Add(new person(){ name="wer", age="38" });
List<string> strlst = new List<string>();
strlst.Add("abc");
strlst.Add("zxc");
right now i am validating the list
lst.Exists(a => strlst.Contains(a.name))
How can I validate the entire list if it contains 'abcandxyz`?

If you find the Intersect of the two names you get the names common to both lists. If that intersection is the same size as your string list then it means all of them are in the intersection, which means they're all in the other list.
return list.Select(person => person.name)
.Intersect(strlst).Count() == strlst.Count();

Correct me if I'm wrong, but I believe your original intent is to validate against your lst variable, not strlst. If it's for strlist, then I believe #LosManos's answer is a very good approach. If you are trying to validate List<person> lst with the values in strlst then you should do the following:
var allNames = lst.Select(l => l.name);
var containsAll = strlist.All(s => allNames.Contains(s));
This way would also ensure that you could do it correctly even if you have more than two things you need to compare on.

Related

How can I get a list of all strings "greater" than a specific value in a List<string>?

Consider the following scenario. I have a list of strings.
var list = new List<string> { "Ringo", "John", "Paul", "George" };
I need to sort the list and return ALL values after a specific value. For instance, if the value I need to filter off of the name "George", I want to return:
{ "John", "Paul", "Ringo" }
Sorting using standard List methods or linq is simple enough, but since these are text strings, I'm drawing a blank on figuring out how to take all values after a specific filter since you can't us a greater-than sign in your where clause.
How can I do this. Linq is preferable but not required.
You can try querying with a help of Linq while using StringComparer:
var list = new List<string> {"Ringo", "John", "Paul", "George" };
string value = "George";
var result = list
.Where(item => StringComparer.OrdinalIgnoreCase.Compare(item, value) > 0)
.OrderBy(item => item)
.ToList(); // if you want to get a list as an answer

Using LINQ with a WHERE to ask for multiple possible results without redundant "||" commands

This is a cosmetics issue, it is syntactical sugar only, just because I want to do it. But basically I have a lot of code that reads like this ... I am using a dynamic for the sheer purpose of time saving and example.
var terms = new List<string> {"alpha", "beta", "gamma", "delta", "epsilon", "rho"};
var list = new List<dynamic> {
new {
Foo = new List<string> {
"alpha",
"gamma"
}
}
};
var result = list
.Where(
n => n.Foo.Contains(terms[0]) ||
n.Foo.Contains(terms[1]) ||
n.Foo.Contains(terms[2]) ||
n.Foo.Contains(terms[3]) ||
n.Foo.Contains(terms[4]) ||
n.Foo.Contains(terms[5]))
.ToList();
Obviously this is a ludicrous hyperbole for the sheer sake of example, more accurate code is ...
Baseline =
Math.Round(Mutations.Where(n => n.Format.Is("Numeric"))
.Where(n => n.Sources.Contains("baseline") || n.Sources.Contains("items"))
.Sum(n => n.Measurement), 3);
But the basic point is that I have plenty of places where I want to check to see if a List<T> (usually List<string>, but there may at times be other objects. string is my present focus though) contains any of the items from another List<T>.
I thought that using .Any() would work, but I actually haven't been able to get that to function as expected. So far, only excessive "||" is all that yields the correct results.
This is functionally fine, but it is annoying to write. I wanted to know if there is a simpler way to write this out - an extension method, or a LINQ method that perhaps I've not understood.
Update
I am really aware that this may be a duplicate, but I am having a hard time figuring out the wording of the question to a level of accuracy that I can find duplicates. Any help is much appreciated.
Solution
Thank you very much for all of the help. This is my completed solution. I am using a dynamic here just to save time on example classes, but several of your proposed solutions worked.
var terms = new List<string> {"alpha", "beta", "gamma", "delta", "epsilon", "rho"};
var list = new List<dynamic> {
new { // should match
Foo = new List<string> {
"alpha",
"gamma"
},
Index = 0
},
new { // should match
Foo = new List<string> {
"zeta",
"beta"
},
Index = 1
},
new { // should not match
Foo = new List<string> {
"omega",
"psi"
},
Index = 2
},
new { // should match
Foo = new List<string> {
"kappa",
"epsilon"
},
Index = 3
},
new { // should not match
Foo = new List<string> {
"sigma"
},
Index = 4
}
};
var results = list.Where(n => terms.Any(t => n.Foo.Contains(t))).ToList();
// expected output - [0][1][3]
results.ForEach(result => {
Console.WriteLine(result.Index);
});
I thought that using .Any() would work, but I actually haven't been able to get that to function as expected.
You should be able to make it work by applying Any() to terms, like this:
var result = list
.Where(n => terms.Any(t => n.Foo.Contains(t)))
.ToList();
You could try this one:
var result = list.Where(terms.Contains(n.Foo))
.ToList();
I assume n.Foo is a string rather than a collection, in which case:
var terms = new List<string> { "alpha", "beta", "gamma", "delta", "epsilon", "rho" };
var list = (new List<string> { "alphabet", "rhododendron" })
.Select(x => new { Foo = x });
var result = list.Where(x => terms.Any(y => x.Foo.Contains(y)));
You want to find out if Any element in one collection exists within another collection, so Intersect should work nicely here.
You can modify your second code snippet accordingly:
var sources = new List<string> { "baseline", "items" };
Baseline =
Math.Round(Mutations.Where(n => n.Format.Is("Numeric"))
.Where(n => sources.Intersect(n.Sources).Any())
.Sum(n => n.Measurement), 3);
Regarding the part of the docs you quoted for "Intersect":
Produces the set intersection of two sequences by using the default equality comparer to compare values.
Every object can be compared to an object of the same type, to determine whether they're equal. If it's a custom class you created, you can implement IEqualityComparer and then you get to decide what makes two instances of your class "equal".
In this case, however, we're just comparing strings, nothing special. "Foo" = "Foo", but "Foo" ≠ "Bar"
So in the above code snippet, we intersect the two collections by comparing all the strings in the first collection to all the strings in the second collection. Whichever strings are "equal" in both collections end up in a resulting third collection.
Then we call "Any()" to determine if there are any elements in that third collection, which tells us there was at least one match between the two original collections.
If performance is an issue when using Any() you can use a regular expression instead. Obviously, you should probably measure to make sure that regular expressions performs faster:
var terms = new List<string> { "alpha", "beta", "gamma", "delta", "epsilon", "rho" };
var regex = new Regex(string.Join("|", terms));
var result = list
.Where(n => regex.Match(n.Foo).Success);
This assumes that joining the terms to a list creates a valid regular expression but with simple words that should not be a problem.
One advantage of using a regular expression is that you can require that the terms are surrounded by word boundaries. Also, the predicate in the Where clause may be easier to understand when compared to a solution using Contains inside Any.

How to remove identical items from List<string>?

I have a List in which I select users from db each time a sql query runs with certain value and selects one user in the time thus I cannot limit identical users in sql.
I have list with:
list[0] = "jerry"
list[1] = "tom"
list[2] = "jerry"
I want any (first or last doesn't matter in my case) to be removed from the list.
Thanks
IEnumerable<string> uniqueUsers = list.Distinct();
You can also use a HashSet:
HashSet<string> uniqueUsers = new HashSet<string>(list);
LINQ can solve this:
List<string> names = new List<string> { "Tom", "Jerry", "Tom" };
IQueryable<string> distinctItems = names.Distinct();
If you want a list type, simply call ToList():
distinctItems.ToList();
Here's an example from the MSDN.
EDIT: Non-LINQ Example (using Contains() from the List class):
List<string> names = new List<string> { "Tom", "Jerry", "Tom" };
List<string> distinctNames = new List<string>();
foreach (var name in names)
{
if (!distinctNames.Contains(name))
{
distinctNames.Add(name);
}
}
You can use the Distinct() LINQ extension.
var list = new List<string> { "Tom", "Jerry", "Tom" };
var uniqueList = list.Distinct();
Using Distinct, as suggested in the other answers, will leave your original list intact and return a separate IEnumerable<> sequence containing the distinct items from your list.
An alternative would be to remove duplicates from your original list directly, using RemoveAll:
var temp = new HashSet<string>();
yourList.RemoveAll(x => !temp.Add(x));
you can use list.distinct();

Merging List<> and mainting identity

I have 3 .net Lists items, I need to merge them all into one, to order them and bind them to a datagrid. However, I need a way of indicating which original list each item came from, so that I can identify this in the datagrid (change color or font etc).
Can anyone suggest the best way to do this?
List<Foo> list1 = new List<Foo>();
List<Foo> list2 = new List<Foo>();
List<Foo> list3 = new List<Foo>();
var query = list1.Select(foo => new { foo, list = "list1" })
.Concat(list2.Select(foo => new { foo, list = "list2" }))
.Concat(list3.Select(foo => new { foo, list = "list3" }))
.OrderBy(item => item.foo); // whatever you need to order by
Expand the properties as needed.
Assuming that your lists contains items of classes that you can amend I'd suggest that you add a property to those classes that keeps track of which type of the 3 it is. Either as an enum or possibly a reference to the actual list that contained it if you might need to refer back.
If you're not able to do that but assuming that they do contain a name property or similar and it's a readonly grid, a very ugly way would be to add a specific prefix/postfix to the name that says where it came from and then just remove that prefix/postfix before showing it on the screen.
Simple solution, assuming you don't want to modify the original class, or it's a primitive, you can use anonymous types:
var resultList = list1.Select(value => new {value, list = list1})
.Concat(list2.Select(value => new {value, list = list2})
.Concat(list3.Select(value => new {value, list = list3})))
.ToList();
I'd go with something like this:
List<object> list1 = new List<object>();
List<object> list2 = new List<object>();
List<object> list3 = new List<object>();
List<KeyValuePair<int, object>> mergedList = new List<KeyValuePair<int, object>>();
mergedList.AddRange(list1.Select(obj => new KeyValuePair<int, object>(1, obj)));
mergedList.AddRange(list2.Select(obj => new KeyValuePair<int, object>(2, obj)));
mergedList.AddRange(list3.Select(obj => new KeyValuePair<int, object>(3, obj)));
The better solution though, would be to add a property to your object that is some kind of enumeration that tells you something about the object itself. The lists themselves are metadata of some sort - list1 is a list of X, not just a list, so all of it's elements should have some kind of notion of X.

Remove items from one list in another

I'm trying to figure out how to traverse a generic list of items that I want to remove from another list of items.
So let's say I have this as a hypothetical example
List<car> list1 = GetTheList();
List<car> list2 = GetSomeOtherList();
I want to traverse list1 with a foreach and remove each item in List1 which is also contained in List2.
I'm not quite sure how to go about that as foreach is not index based.
You can use Except:
List<car> list1 = GetTheList();
List<car> list2 = GetSomeOtherList();
List<car> result = list2.Except(list1).ToList();
You probably don't even need those temporary variables:
List<car> result = GetSomeOtherList().Except(GetTheList()).ToList();
Note that Except does not modify either list - it creates a new list with the result.
You don't need an index, as the List<T> class allows you to remove items by value rather than index by using the Remove function.
foreach(car item in list1) list2.Remove(item);
In my case I had two different lists, with a common identifier, kind of like a foreign key.
The second solution cited by "nzrytmn":
var result = list1.Where(p => !list2.Any(x => x.ID == p.ID && x.property1 == p.property1)).ToList();
Was the one that best fit in my situation.
I needed to load a DropDownList without the records that had already been registered.
Thank you !!!
This is my code:
t1 = new T1();
t2 = new T2();
List<T1> list1 = t1.getList();
List<T2> list2 = t2.getList();
ddlT3.DataSource= list2.Where(s => !list1.Any(p => p.Id == s.ID)).ToList();
ddlT3.DataTextField = "AnyThing";
ddlT3.DataValueField = "IdAnyThing";
ddlT3.DataBind();
I would recommend using the LINQ extension methods. You can easily do it with one line of code like so:
list2 = list2.Except(list1).ToList();
This is assuming of course the objects in list1 that you are removing from list2 are the same instance.
list1.RemoveAll(l => list2.Contains(l));
You could use LINQ, but I would go with RemoveAll method. I think that is the one that better expresses your intent.
var integers = new List<int> { 1, 2, 3, 4, 5 };
var remove = new List<int> { 1, 3, 5 };
integers.RemoveAll(i => remove.Contains(i));
Solution 1 : You can do like this :
List<car> result = GetSomeOtherList().Except(GetTheList()).ToList();
But in some cases may this solution not work. if it is not work you can use my second solution .
Solution 2 :
List<car> list1 = GetTheList();
List<car> list2 = GetSomeOtherList();
we pretend that list1 is your main list and list2 is your secondry list and you want to get items of list1 without items of list2.
var result = list1.Where(p => !list2.Any(x => x.ID == p.ID && x.property1 == p.property1)).ToList();
As Except does not modify the list, you can use ForEach on List<T>:
list2.ForEach(item => list1.Remove(item));
It may not be the most efficient way, but it is simple, therefore readable, and it updates the original list (which is my requirement).
I think it would be quick to convert list A to a dictionary and then foreach the second list and call DictA.Remove(item) otherwise I think most solutions will cause many iterations through list A either directly or under the covers.
If the lists are small, it probably won't matter.
In case you have two different list with different DataModals
List<FeedbackQuestionsModel> feedbackQuestionsList = new();
List<EmployeesFeedbacksQuestionsModel> employeeQuestionsList = new();
var resultList = feedbackQuestionsList.Where(p => !employeeQuestionsList.Any(x => x.Question == p.Question)).ToList();
feedbackQuestionsList = resultList.ToList();
Here ya go..
List<string> list = new List<string>() { "1", "2", "3" };
List<string> remove = new List<string>() { "2" };
list.ForEach(s =>
{
if (remove.Contains(s))
{
list.Remove(s);
}
});

Categories

Resources