I have a question about check for if object in one List exists in another and if not add them into second list all by Linq. Actually I have two loops with one condition:
foreach (var p in seznamVlaku.Select(s => s.ProjizdejiciStanicemi)) {
foreach (var l in p) {
if(_nodes.Any(a => a.ID != l.Key.ID)){
_nodes.Add(new Node() {Name = l.Key.Jmeno, ID = l.Key.ID, X = l.Key.X, Y = l.Key.Y });
}
}
}
It is possible do this faster by Linq query?
I don't think there is a much faster way, you have to check if l already exists in _nodes, and that for each l. If you could optimize that on a higher level I can't tell without knowing what this is doing.
If you simply want a shorter LINQ statement, you can use SelectMany:
foreach(var l in sznamVlaku.SelectMany(s => s.ProjizdejiciStanicemi)
.Where(x => _nodes.All(a => a.ID != x.Key.ID)))
_nodes.Add(new Node() {Name = l.Key.Jmeno, ID = l.Key.ID, X = l.Key.X, Y = l.Key.Y });
Note that I used All instead of Any, because you want to find all l where all nodes have a different ID.
You don't need two foreach. Instead use SelectMany.
Your example:
foreach (var p in seznamVlaku.Select(s => s.ProjizdejiciStanicemi))
{
foreach (var l in p)
{
}
}
We can write like and it'd be the same:
foreach (var node in seznamVlaku.SelectMany(list => list.ProjizdejiciStanicemi))
{
}
You can add condition (existing item) add to pipeline of linq query
Code:
foreach (var node in seznamVlaku
.SelectMany(list => list.ProjizdejiciStanicemi)
.Where(item => nodes
.Exists(node => node.ID != item.ID)))
{
_nodes.Add(new Node() {Name = node.Key.Jmeno, ID = node.Key.ID, X = node.Key.X, Y = node.Key.Y });
}
The following code should be considerably faster because it uses hashing instead of nested loops:
// build a HashSet of your key's type (I'm assuming integers here) containing all your current elements' keys in the _nodes ObservableCollection
HashSet<int> hashSet = new HashSet<int>(_nodes.Select(n => n.ID));
foreach (var l in seznamVlaku.SelectMany(s => s.ProjizdejiciStanicemi)) {
// if you can add the element's ID to the HashSet it hasn't been added before
if(hashSet.Add(l.Key.ID)) {
_nodes.Add(new Node() {Name = l.Key.Jmeno, ID = l.Key.ID, X = l.Key.X, Y = l.Key.Y });
}
}
Related
I'm trying to make a listbox where i can add items to it using datagridview, the thing is i want to determine which item is duplicate and how many times it duplicate.
item1
item1
item2
item2
item2
output item1=2, item2=3
Here is the one that i tried which shows the last item that have been duplicate
int count = 0;
for (int i = 0; i < listBox1.Items.Count; i++)
{
var s = listBox1.Items[i].ToString();
if (s.StartsWith(listfood))
{
if (s == listfood)
{
++count;
}
}
}
MessageBox.Show(count.ToString());
Try
var duplicateItems = listBox1.Items.GroupBy(x => x.ToString())
.Where(x => x.Count() > 1)
.Select(x => new { Value = x.Key, Count = x.Count() })
.ToList();
using System.Linq;
// ...
var duplicates = listBox1.Items.GroupBy(x => x)
.Where(g => g.Count() > 1)
.Select(y => new { ItemName = y.Key, Occurrences = y.Count() })
.ToList();
foreach (var duplicate in duplicates)
MessageBox.Show($"{duplicate.ItemName}: {duplicate.Occurrences}");
This solution uses LINQ to query the listBox1's Items collection and filter out any data we don't care about.
First, we use GroupBy to sort the items. Then, Where will filter out any items in the collection that only exist once. Select allows us to "project" the items remaining in the filtered collection into a "new form" (we use an anonymous type with an ItemName and Occurrences property to track the names of the duplicates and the number of times it appears in the collection).
Finally, ToList converts the collection from an IEnumerable<string> to aListtype.ToListis optional depending on how you plan on usingduplicates. In fact, my example doesn't need to callToListbecause aforeachloop can iterate over anIEnumerable` collection.
I know the Answers above will definitely work, but i can't understand it and make it work. This one works for me, where i transfer values of listbox to an array and check the duplicates inside that array.
var list = new List<string>();
foreach(var item in listBox1.Items)
{
list.Add(item.ToString());
}
var r = from b in list
group b by b into g
let count = g.Count()
orderby count descending
select new { Value = g.Key, Count = count };
foreach(var x in q)
{
MessageBox.Show("value: " + b.Value + " Count:" + b.Count);
}
Found my answer here
I have the following foreach statements, which I want to transfer into linq query.
var equalityGroup= new Dictionary<string, List<string>();
var firstGroup = new Dictionary<string, List<string>();
var request = new List<Request>();
foreach(var element in request)
{
var key = element.Number;
if (!equalityGroup.ContainsKey(key))
{
equalityGroup.Add(key, new List<string>());
}
foreach(var item in firstGroup)
{
var query = item.Value.FindAll(y => y ==element.Id);
if (query.Any())
{
equalityGroup[key].AddRange(query);
}
}
}
Can someone give me a good example for Linq that will work as this foreaches?
I think you should be able to greatly increase the performance for large collections by performing a join (which uses hash-tables internally) instead of nested loops.
var firstGroup = new Dictionary<string, List<string>>();
var request = new List<Request>();
var q = from element in request
join y in firstGroup.SelectMany(x => x.Value) on element.Id equals y
group y by element.Id into g
select new { g.Key, g };
var equalityGroup = q.ToDictionary(x => x.Key, x => x.g.ToList());
New to C# and appreciate any help. The issue is that I need to filter the results of my api call against an array (using an "allowedA" and "allowedB" array.) I don't know how to edit the lambda expression to check against the loop.
var activities = await _restClientTaxonomy.GetTaxonomyFullAsync(TAXONOMY_CLASSIFICATIONID_FOR_ACTIVITY);
var activityTypes = await _restClientTaxonomy.GetTaxonomyFullAsync(TAXONOMY_CLASSIFICATIONID_FOR_ACTIVITY_TYPES);
var documentEventxx = activities.Select(type => type.Id);
long [] allowedA = new long []{ 7137, 40385637};
long [] allowedB = new long []{ 7137, 40385637};
foreach (long value in documentEventxx)
{
foreach (var item in allowed)
{
if (item == value) {
//These are the values I am looking for -> values that are part of the documentEventxx and allowedB.
}
}
}
var result = activityTypes.Select(type => new CategoryViewModel
{
Id = type.Id,//This is where I want to add only items that are in the allowedA array
Text = type.Name,
Types = activities.Where(a => a.ParentId == type.Id).Select(t => new TaxonomyMemberTextItem
{
Id = t.Id, //This is where I want to add only items that are in the allowedB array
Text = t.Name
}).ToList()
}).ToArray();
I have been reading about lambda expressions and foreach loops so please don't just post a random link.
Thanks in advance.
Filter the values before Selecting.
activityTypes.Where(x=>allowedA.Contains(x.Id)).Select(type => new CategoryViewModel
{
Id = type.Id,
Text = type.Name,
Types = activities.Where(a => a.ParentId == type.Id && allowedB.Contains(a.Id)).Select(t => new TaxonomyMemberTextItem
{
Id = t.Id,
Text = t.Name
}).ToList()
})
To filter you use .Where. You .Select to create a list of new types. So in order to filter, then create the lists of objects you want:
var result = activityTypes.Where(type=>isAllowed(type.Id)).Select(type => new CategoryViewModel
{
Id = type.Id,//This is where I want to add only items that are in the allowedA array
Text = type.Name,
Types = activities.Where(a => a.ParentId == type.Id&&isAllowed(a.Id)).Select(t => new TaxonomyMemberTextItem
{
Id = t.Id, //This is where I want to add only items that are in the allowedB array
Text = t.Name
}).ToList()
}).ToArray();
This is what I have:
List<Person> list = new List<Person>()
{
new Person { Name="test", Age=1 },
new Person { Name="tester", Age=2 }
};
var items = list.Select(x =>
{
return new
{
Name = x.Name
};
});
foreach (object o in items)
{
Console.WriteLine(o.GetType().GetProperty("Name").GetValue(o, null));
}
I feel like I'm not doing it correctly.
Is there a simpler way to access properties of anonymous types in a collection?
Use the var keyword in the foreach line as well, instead of the general object type. The compiler will then automatically resolve the anonymous type and all its members, so you can access the properties directly by name.
foreach (var o in items)
{
Console.WriteLine(o.Name);
}
var items = list.Select(x =>new { Name = x.Name });
foreach (var o in items)
{
Console.WriteLine(o.Name);
}
Just use var and you'll have complete type support
Why not just this?
var items = list.Select(x => x.Name);
foreach (var o in items)
Console.WriteLine(o);
You're only getting a single field, no need to create another anonymous type.
The previous answers are sufficient enough.
Just about simplification, notice than you didn't reacj the maximal simplification possible.
You can write
list.ForEach(person => Console.WriteLine(person.Name));
or
list.Select(person => person.Name).ToList().ForEach(Console.WriteLine);
If you're going to iterate through the whole anonymous collection anyway, you could ToList() it and use the List.ForEach() method:
List<Person> list = new List<Person>()
{
new Person { Name="test", Age=1},
new Person { Name="tester", Age=2}
};
var items = list.Select(x =>
{
return new
{
Name = x.Name
};
}).ToList();
items.ForEach(o => Console.WriteLine(o.Name));
I want to use LINQ to convert this
IEnumerable<int>[] value1ByType = new IEnumerable<int>[3];
value1ByType[0]= new [] { 0};
value1ByType[1]= new [] {10,11};
value1ByType[2]= new [] {20};
var value2ToType = new Dictionary<int,int> {
{100,0},
{101,1},
{102,2},
{103,1}};
to this
var value2ToValue1 = new Dictionary<int,int> {
{100, 0},
{101,10},
{102,20},
{103,11}};
Is there a way to do this with LINQ? Without LINQ I would use multiple IEnumerators, one for each IEnumerable of value1ByType. like this:
// create enumerators
var value1TypeEnumerators = new List<IEnumerator<int>>();
for (int i = 0; i < value1ByType.Length; i++)
{
value1TypeEnumerators.Add(value1ByType[i].GetEnumerator());
value1TypeEnumerators[i].MoveNext();
}
// create wanted dictionary
var value2ToValue1 = new Dictionary<int, int>();
foreach (var item in Value2ToType)
{
int value1=value1TypeEnumerators[item.Value].Current;
value2ToValue1.Add(item.Key, value1);
value1TypeEnumerators[item.Value].MoveNext();
}
Any Idea how to do this in LINQ?
Not pure but you can at least do ...
var enumerators = value1ByType.Select(v => v.GetEnumerator()).ToArray();
var value2ToValue1 = value2ToType
.ToDictionary(x => x.Key, x => { enumerators[x.Value].MoveNext(); return enumerators[x.Value].Current; });
But there are so many ways this could go wrong it begs the question - why was the data in those data-structures anyway? and can you fix that instead? How did you end up with exactly the right number of references in the 2nd data structure to elements in the first?
I'm pretty sure that #Hightechrider's solution is most performant than this one, but if you really like the syntax sugar way, you can do it like this:
public IDictionary<int, int> MergeSequences(IEnumerable<int>[] value1ByType, Dictionary<int, int> value2ToType)
{
int pos = 0;
var value1ByTypePos = from byType in value1ByType
select new { Pos = pos++, Enumerator = byType.GetEnumerator() };
return (from byType in value1ByTypePos
join toType in value2ToType
on byType.Pos equals toType.Value
select new { toType.Key, Value = byType.Enumerator.GetNext() })
.ToDictionary(pair => pair.Key, pair => pair.Value);
}
I've added an extension method to the IEnumerator interface like this:
public static T GetNext<T>(this IEnumerator<T> enumerator)
{
if (!enumerator.MoveNext())
throw new InvalidOperationException();
return enumerator.Current;
}
Now you have to be aware that any of this solutions can give you slightly different results, depending on how elements in the dictionary are enumerated. For example, another valid result to this code is:
var value2ToValue1 = new Dictionary<int,int> {
{100, 0},
{103, 10},
{102, 20},
{101, 11}};
Notice that now 101 is paired with 11 and 103 is paired with 10. If this is a problem, then you should use a SortedDictionary<int, int> when defining value2ToType variable.
What you can do for sure is replace the first part with the following:
var value1TypeEnumerators = value1ByType.ToList();
instead of using an enumerator.
If I do not care about performance I could also write:
var value2Ordered = Value2ToType.OrderBy(x => x.Value).Select(x=>x.Key);
var value1Ordered = from item in value1ByType from subitem in item select subitem;
var value2ToValue1 = value2Ordered.Zip(value1Ordered, (x, y) => new { Key = x, Value = y })
.ToDictionary(item => item.Key, item => item.Value);
I used the zip method from a stackoverflow community wiki. I didn't test this with the c#4.0 zip method