Removing item from inner list - linq - c#

I have list list1, which contains another list, list2.
I have to remove an item from list2 of list1 where id=2 using lambda expression.
How can i write it.?
eg: list1 -> List<balls> -> Ball contains list of images.
list2 -> List<images> -> each image will have an id.
i need to remove images for some balls from list1(where image id is given as 1)

You can try with this:
list1.ForEach(ball =>
ball.list2.RemoveAll(image => image.Id == 2));

Something like
list1.First(k => k.id == 2)
.list2.RemoveAt(0);
If your id refers to list2, you have to make loop.
foreach (var item in list1)
{
item.list2.RemoveAll(k => k.id == 2);
}
Or alternatively,
list1.ForEach(item => item.list2.RemoveAll(k => k.id == 2));

Related

c# - How to remove matching items from a list using Linq or otherwise

I'm trying to remove matching items from a list, which seems like a pretty simple task, but as luck would have it, I can't figure it out.
Example list:
List<int> points1 = new List<int>
{
1, 2, 3, 3
};
I'm trying to get uniquePoints1 to be 1,2
I know there is .Distinct() but that would return 1,2,3 which is not what I want.
I've also tried the following along with .Distinct() but I get a red line saying Comparison made to the same variable, did you mean to compare to something else?
List<int> uniquePoints1 = points1.Where(x => x == x);
List<int> uniquePoints1 = points1.RemoveAll(x => x == x);
Any help or direction is appreciated.
You can use the GroupBy method to group the items, and then return only the numbers from groups that have a count of 1:
List<int> uniquePoints = points
.GroupBy(x => x) // Group all the numbers
.Where(g => g.Count() == 1) // Filter on only groups that have one item
.Select(g => g.Key) // Return the group's key (which is the number)
.ToList();
// uniquePoints = { 1, 2 }
"Group by" to the rescue!
This is a LINQ variant -- see other answers for a non-LINQ version
var nonDuplicatedPoints = from p in points1
group p by p into g
where g.Count() == 1
select g.Key;

How can i remove same item in list

Could you help me? I cant remove the same item in a list.
List<string> text = new List<string>();
text.Add("A");
text.Add("B");
text.Add("C");
text.Add("D");
text.Add("D");
text.Add("A");
foreach(string i in text)
{
Console.WriteLine(i);
}
the result is A,B,C,D,D,A but I need to be B,C . How can i do?
Here is my solution,
var result = text.GroupBy(x => x).Where(y => y.Count() == 1).Select(z => z.Key);
Console.WriteLine(string.Join(", ", result));
Explanation:
GroupBy(x => x): This will group list based on characters i.e predicate.
.Where(y => y.Count() == 1): This will filter elements which are duplicates.
.Select(z => z.Key): Select will create new enumerable which contains Keys from Grouped elements
Something like
text.GroupBy(t => t).Where(tg => tg.Count()==1).Select(td => td.First());
This proberly wont compile, you need to fix that your self.
The idea is:
1. Group by item.
2. Take all groups with exactly 1 item
3. Select the Item

Two for loops in lambda expression

How to create the exactly following two for's in lambda expression?
foreach (var item in list1)
{
foreach (var item2 in list2)
{
if (item.number == item2.number)
{
return false;
}
}
}
Since you're just checking to see if any one item matches, you can use Any().
return !list1.Any( item1 => list2.Any(item2 => item2 == item1 ));
I would just use the Intersect function available for lists and this will return you all the elements that are common in 2 lists. If you just want to see if one exists then you can do it very easily by checking the count.
int count = List1.Select(s => s.number).Intersect(List2.Select(s => s.number)).Count;
If you want to know which elements are unique in both lists then use the Exclude method.
var uniqueItems = List1.Select(s => s.number).Except(List2.Select(s => s.number));
Here you go !!
Using Linq Method Syntax :
!list1.Any(item => list2.Any(item2 => item.number == item2.number))
Using Linq Query syntax:
!(from item in list1
from item2 in list2
where item.number==item2.number select item).Any()

How do I convert a list of lists to dictionary in C#?

I have a list of boxes(unique, with id) and in each box there are certain items(unique, with id).
Example:
list<box> boxes = new list<boxes>;
where,
class box
{ ...
list<item> items = new list<item>;
...
}
Box1: item1, item2, ...
Box2: item4, item5, ...
Box3: ...
I need to find the item details, given the item id. For this I current do something like this:
foreach (box b in boxes)
{
foreach (item i in b.items)
{
if (i.id == searchId)
return i;
}
}
Question is: How can I convert this list data structure to a dictionary data structure?
As I have keys (Id), so I think using a dictionary would be a better choice?
If it's possible that same items can exist in several boxes, you can select all items, and group them by id, then select first item from each group as a value for dictionary:
Dictionary<int, item> items = boxes.SelectMany(b => b.items)
.GroupBy(i => i.id)
.ToDictionary(g => g.Key, g.First());
If all items have unique ids:
var items = boxes.SelectMany(b => b.items) .
.ToDictionary(i => i.id);
Getting item will look like:
if (items.ContainsKey(searchId))
return items[searchId];
As #Douglas stated, to avoid double lookup it's better to use TryGetValue method:
item i;
if (items.TryGetValue(searchId, out i))
return i;
NOTE: Linq alternative without dictionary will be (it does exactly same as your code - enumerates boxes and their items for each search):
var item = boxes.SelectMany(b => b.items).FirstOrDefault(i => i.id == searchId);
So, if you don't want to hold dictionary with items between searches, or if you need to execute single search, then you can use this solution.
Assuming all your items are unique:
var dictionary = boxes.SelectMany(box => box.items).ToDictionary(item => item.id);
You can then look up values using:
item i;
if (dictionary.TryGetValue(searchID, out i))
return i;

Linq query

I'm a big noob with Linq and trying to learn, but I'm hitting a blocking point here.
I have a structure of type:
Dictionary<MyType, List<MyObj>>
And I would like to query with Linq that structure to extract all the MyObj instances that appear in more than one list within the dictionary.
What would such a query look like?
Thanks.
from myObjectList in myObjectDictionary.Values
from myObject in myObjectList.Distinct()
group myObject by myObject into myObjectGroup
where myObjectGroup.Skip(1).Any()
select myObjectGroup.Key
The Distinct() on each list ensures MyObj instances which repeat solely in the same list are not reported.
You could do something like this:
var multipleObjs =
MyObjDictionary.Values // Aggrigate all the List<MyObj> values into a single list
.SelectMany(list => list) // Aggrigate all the MyObjs from each List<MyObj> into a single IEnumerable
.GroupBy(obj => obj) // Group by the Obj itself (Or an ID or unique property on them if it exists)
.Where(group => group.Count() >= 2) // Filter out any group with less then 2 objects
.Select(group => group.Key); // Re-Select the objects using the key.
Edit
I Realized that this could also be read diffrently, such that it doesn't matter if the MyObj occurs multiple times in the same list, but only if it occurs multiple times in diffrent lists. In that case, when we are initally aggrigating the lists of MyObjs we can select Distinct values, or use a slightly diffrent query:
var multipleObjs =
MyObjDictionary.Values // Aggrigate all the List<MyObj> values into a single list
.SelectMany(v => v.Distinct()) // Aggrigate all distinct MyObjs from each List<MyObj> into a single IEnumerable
.GroupBy(obj => obj) // Group by the Obj itself (Or an ID or unique property on them if it exists)
.Where(group => group.Count() >= 2) // Filter out any group with less then 2 objects
.Select(group => group.Key); // Re-Select the objects using the key.
var multipleObjs =
MyObjDictionary.SelectMany(kvp => // Select from all the KeyValuePairs
kvp.Value.Where(obj =>
MyObjDictionary.Any(kvp2 => // Where any of the KeyValuePairs
(kvp.Key != kvp2.Key) // Is Not the current KeyValuePair
&& kvp.Value.Contains(obj)))); // And also contains the same MyObj.

Categories