I have the following object:
public class Foo
{
public Int32 Id
public Int32 SampleId
public Int32 CompanyId
public Decimal Data
}
public class Bar
{
public Int32 CompanyId
public Decimal Data
}
I have a list of these objects. I want to perform a calculation where I group the Ids by "CompanyId" first. Then for each company ID, add 3 different SampleIds Data together and returning a new object for each company.
//I want to get the data from SampleId = 2, 4 and 6 added together
//from the Foo object and put into the Data of the new Bar object.
List.GroupBy(l => l.CompanyId).Select( x => new Bar { CompanyId = x.Key, ????? } );
I am stuck with how to perform the calculation after I do the grouping. Any help is much appreciated.
You look to be pretty close to me.
This should work:
var list = new List<Foo>
{
new Foo { CompanyId = 1, Data = 15, Id = 1, SampleId = 2 },
new Foo { CompanyId = 1, Data = 10, Id = 2, SampleId = 4 },
new Foo { CompanyId = 1, Data = 25, Id = 2, SampleId = 6 }
};
var output = list.GroupBy(
l => l.CompanyId,
(key, data) => new Bar { CompanyId = key, Data = data.Sum(d => d.Data) });
Or if you want to filter out just 2,4,6 as sample id (can't say I understand why to be honest) then this could work:
[Test]
public void Testing()
{
var list = new List<Foo>
{
new Foo { CompanyId = 1, Data = 15, Id = 1, SampleId = 2 },
new Foo { CompanyId = 1, Data = 10, Id = 2, SampleId = 4 },
new Foo { CompanyId = 1, Data = 25, Id = 3, SampleId = 8 },
new Foo { CompanyId = 1, Data = 25, Id = 4, SampleId = 12 },
new Foo { CompanyId = 1, Data = 25, Id = 5, SampleId = 14 }
};
var filterList = new List<int> { 2, 4, 6 };
var output = list.Where(l => filterList.Contains(l.SampleId))
.GroupBy(l => l.CompanyId, (key, data) => new Bar { CompanyId = key, Data = data.Sum(d => d.Data) });
Assert.True(output != null);
Assert.True(output.FirstOrDefault() != null);
Assert.True(output.FirstOrDefault().Data == 25);
}
Related
I have 2 list
IEnumerable<int> Ids, IEnumerable<Guid> GuidIds
for sample data
IEnumerable<int> ids1 = new List<int>() { 1, 2, 4 };
IEnumerable<Guid> guidIds = new List<Guid>() { new Guid("F44D7A64-8BDE-41E1-810F-B24377AD7F94"), new Guid("F44D7A64-8BDE-41E1-810F-B24377AD7F96"), new Guid("F44D7A64-8BDE-41E1-810F-B24377AD7F97") };
and a class
public class ClassEnd
{
public int Id { get; set; }
public Guid GuidId { get; set; }
}
I want to merge into this by Linq query
IEnumerable<ClassEnd> mergeList = new List<ClassEnd>()
{
new ClassEnd() { Id = 1, CompanyId = new Guid("F44D7A64-8BDE-41E1-810F-B24377AD7F94") },
new ClassEnd() { Id = 2, CompanyId = new Guid("F44D7A64-8BDE-41E1-810F-B24377AD7F96") },
new ClassEnd() { Id = 3, CompanyId = new Guid("F44D7A64-8BDE-41E1-810F-B24377AD7F97") }
};
Could you please help me with how to merge like the above "mergeList" by using Linq?
If lists are of the same size - it can be easily achieved with Enumerable.Zip:
var classEnds = ids1
.Zip(guidIds, (i, guid) => new ClassEnd
{
Id = i,
GuidId = guid
})
.ToList();
I have a List of an object (exobject in the below code sample) who each have SomeId, AnotherId, SomeOtherId and Timestamp. This list might have duplicate entries with each record having a different Timestamp.
I want to remove all duplicates of this object with older Timestamps and only keep those that are the latest.
Sample object:
SomeId AnotherId SomeOtherId Timestamp
1 2 1 10
1 2 1 20
1 3 2 30
2 3 4 40
1 3 2 50
My required list should be
1,2,1,20 and 1,3,2,50 and 2,3,4,40.
I have a very crude implementation in C# do do this.
for (int i = 0; i < exObject.Count - 1; i++)
{
for (int j = i + 1; j < exObject.Count - 1; j++)
{
if (exObject[i].SomeId == exObject[j].SomeId && exObject[i].AnotherId == exObject[j].AnotherId && exObject[i].SomeOtherId == exObject[j].SomeOtherId)
{
if (exObject[i].TimeStamp < exObject[j].TimeStamp)
exObject[i].TimeStamp = exObject[j].TimeStamp;
exObject.Remove(exObject[j]);
}
}
}
I would like to know if there is a more elegant and nicer way to do this or if there is a lambda I can use to accomplish this.
System.Linq has a Distinct method. You'd have to implement an IEqualityComparer. Details of how here...
https://msdn.microsoft.com/en-us/library/bb338049(v=vs.110).aspx
Edit based on your comment: If you do an orderBy it should keep the one you want... here's some code...
using System.Collections.Generic;
using System.Linq;
namespace ConsoleApplication1
{
class Program
{
static void Main(string[] args)
{
var data = new[]
{
new SomeClass { SomeId = 1, AnotherId = 1, SomeOtherId = 1, Timestamp = 10 },
new SomeClass { SomeId = 1, AnotherId = 1, SomeOtherId = 1, Timestamp = 20 }, // Duplicate
new SomeClass { SomeId = 1, AnotherId = 2, SomeOtherId = 2, Timestamp = 30 },
new SomeClass { SomeId = 1, AnotherId = 2, SomeOtherId = 2, Timestamp = 35 }, // Duplicate
new SomeClass { SomeId = 2, AnotherId = 4, SomeOtherId = 4, Timestamp = 40 },
new SomeClass { SomeId = 3, AnotherId = 2, SomeOtherId = 2, Timestamp = 50 },
new SomeClass { SomeId = 1, AnotherId = 1, SomeOtherId = 1, Timestamp = 50 } // Duplicate
};
var distinctList = data
.OrderBy(x => x.Timestamp)
.Distinct(new SomeClassComparer())
.ToList();
}
public class SomeClass
{
public int SomeId { get; set; }
public int AnotherId { get; set; }
public int SomeOtherId { get; set; }
public int Timestamp { get; set; }
}
public class SomeClassComparer : IEqualityComparer<SomeClass>
{
public bool Equals(SomeClass x, SomeClass y)
{
if (ReferenceEquals(x, y))
{
return true;
}
//Check whether any of the compared objects is null.
if (ReferenceEquals(x, null) || ReferenceEquals(y, null))
{
return false;
}
//Check whether the SomeClass's properties are equal.
return x.SomeId == y.SomeId &&
x.AnotherId == y.AnotherId &&
x.SomeOtherId == y.SomeOtherId;
}
public int GetHashCode(SomeClass someClass)
{
//Check whether the object is null
if (ReferenceEquals(someClass, null))
{
return 0;
}
//Get hash code for the fields
var hashSomeId = someClass.SomeId.GetHashCode();
var hashAnotherId = someClass.AnotherId.GetHashCode();
var hashSomeOtherId = someClass.SomeOtherId.GetHashCode();
//Calculate the hash code for the SomeClass.
return (hashSomeId ^ hashAnotherId) ^ hashSomeOtherId;
}
}
}
}
You can Group By the 3 fields and take the first one of each group:
List
.GroupBy(x=> new {x.prop1, x.prop2, x.prop3 })
.Select(g=> g.OrderByDescending(o=> o.dateprop).First())
.ToList();
Sample that is working perfectly:
static void Main(string[] args)
{
List<Foo> myList = new List<Foo>();
myList.Add(new Foo(1, 2, 1, 10));
myList.Add(new Foo(1, 2, 1, 20));
myList.Add(new Foo(1, 3, 2, 30));
myList.Add(new Foo(2, 3, 4, 40));
myList.Add(new Foo(1, 3, 2, 50));
// The following returns 3 results with 20, 50 and 40 timeStamps.
var results = myList.GroupBy(x => new { x.SomeId, x.AnotherId, x.SomeOtherId })
.Select(g => g.OrderByDescending(o => o.Timestamp).First()).ToList();
}
I want to remove items from a list of entities, when there is a concidence from a list (id). I have written this code, but I am guessing there is a better way to do it, and improve performance.
Here is my code:
List<int> toRemove; //includes the ids of the entities to be removed
if (people.Count > 1)
people.RemoveAll(x => people.Any(y => y != x && toRemove.Contains(x.ID)));
else
people.RemoveAll(x => toRemove.Contains(x.ID));
Given a list of people, for example:
var people = new List<Person>
{
new Person { ID = 1, Name = "Fred1" },
new Person { ID = 2, Name = "Fred2" },
new Person { ID = 3, Name = "Fred3" },
new Person { ID = 4, Name = "Fred4" },
new Person { ID = 5, Name = "Fred5" },
new Person { ID = 6, Name = "Fred6" },
new Person { ID = 7, Name = "Fred7" },
new Person { ID = 8, Name = "Fred8" },
new Person { ID = 9, Name = "Fred9" },
new Person { ID = 10, Name = "Fred10" }
};
And a list of IDs to remove:
List<int> toRemove = new List<int> { 3, 4, 5 };
You can remove the unwanted entries like this:
people = people.Where(p => !toRemove.Contains(p.ID)).ToList();
Oh, and for completeness, here's a Person class to complete the example!
public class Person
{
public int ID { get; set; }
public string Name { get; set; }
}
And to show it working:
https://ideone.com/ERP3rk
i have a two list
List<Sent> SentList;
List<Messages> MsgList;
both have the same property called MsgID;
MsgList SentList
MsgID Content MsgID Content Stauts
1 aaa 1 aaa 0
2 bbb 3 ccc 0
3 ccc
4 ddd
5 eee
i want to compare the MsgID in Msglist with the sentlist and need items which are not in the sent list using linq
Result
MsgID Content
2 bbb
4 ddd
5 eee
You could do something like:
HashSet<int> sentIDs = new HashSet<int>(SentList.Select(s => s.MsgID));
var results = MsgList.Where(m => !sentIDs.Contains(m.MsgID));
This will return all messages in MsgList which don't have a matching ID in SentList.
The naive approach:
MsgList.Where(x => !SentList.Any(y => y.MsgID == x.MsgID))
Be aware this will take up to m*n operations as it compares every MsgID in SentList to each in MsgList ("up to" because it will short-circuit when it does happen to match).
Well, you already have good answers, but they're most Lambda. A more LINQ approach would be like
var NotSentMessages =
from msg in MsgList
where !SentList.Any(x => x.MsgID == msg.MsgID)
select msg;
You can do like this,this is the quickest process
Var result = MsgList.Except(MsgList.Where(o => SentList.Select(s => s.MsgID).ToList().Contains(o.MsgID))).ToList();
This will give you expected output.
You can do something like
var notSent = MsgSent.Except(MsgList, MsgIdEqualityComparer);
You will need to provide a custom equality comparer as outlined on MSDN
http://msdn.microsoft.com/en-us/library/bb336390.aspx
Simply have that equality comparer base equality only on MsgID property of each respective type. Since the equality comparer compares two instances of the same type, you would need to define an interface or common base type that both Sent and Messages implement that has a MsgID property.
Try,
public class Sent
{
public int MsgID;
public string Content;
public int Status;
}
public class Messages
{
public int MsgID;
public string Content;
}
List<Sent> SentList = new List<Sent>() { new Sent() { MsgID = 1, Content = "aaa", Status = 0 }, new Sent() { MsgID = 3, Content = "ccc", Status = 0 } };
List<Messages> MsgList = new List<Messages>() { new Messages() { MsgID = 1, Content = "aaa" }, new Messages() { MsgID = 2, Content = "bbb" }, new Messages() { MsgID = 3, Content = "ccc" }, new Messages() { MsgID = 4, Content = "ddd" }, new Messages() { MsgID = 5, Content = "eee" }};
int [] sentMsgIDs = SentList.Select(v => v.MsgID).ToArray();
List<Messages> result1 = MsgList.Where(o => !sentMsgIDs.Contains(o.MsgID)).ToList<Messages>();
Hope it should help.
In .NET 6 you can take advantage of .ExceptBy(), which lets you define which property of the first list to compare the items in the second list by:
List<Message> result = messages
.ExceptBy(sentList.Select(msg => msg.MsgID), msg => msg.MsgID)
.ToList();
messages is the first list, whereas a collection of the MsgID properties from sentList is the second list.
Example fiddle here.
Note:
.ExceptBy() produces the set difference between the two collections --> only distinct values will be in the resulting collection. This means that if messages contains the same value more than once (e.g. { "aaa", "bbb", "ccc", "ddd", "ddd", "eee" }), any duplicates will be removed in the resulting collection (--> { "bbb", "ddd", "eee" }).
As an extension method
public static IEnumerable<TSource> AreNotEqual<TSource, TKey, TTarget>(this IEnumerable<TSource> source, Func<TSource, TKey> sourceKeySelector, IEnumerable<TTarget> target, Func<TTarget, TKey> targetKeySelector)
{
var targetValues = new HashSet<TKey>(target.Select(targetKeySelector));
return source.Where(sourceValue => targetValues.Contains(sourceKeySelector(sourceValue)) == false);
}
eg.
public class Customer
{
public int CustomerId { get; set; }
}
public class OtherCustomer
{
public int Id { get; set; }
}
var customers = new List<Customer>()
{
new Customer() { CustomerId = 1 },
new Customer() { CustomerId = 2 }
};
var others = new List<OtherCustomer>()
{
new OtherCustomer() { Id = 2 },
new OtherCustomer() { Id = 3 }
};
var result = customers.AreNotEqual(customer => customer.CustomerId, others, other => other.Id).ToList();
Debug.Assert(result.Count == 1);
Debug.Assert(result[0].CustomerId == 1);
List<Person> persons1 = new List<Person>
{
new Person {Id = 1, Name = "Person 1"},
new Person {Id = 2, Name = "Person 2"},
new Person {Id = 3, Name = "Person 3"},
new Person {Id = 4, Name = "Person 4"}
};
List<Person> persons2 = new List<Person>
{
new Person {Id = 1, Name = "Person 1"},
new Person {Id = 2, Name = "Person 2"},
new Person {Id = 3, Name = "Person 3"},
new Person {Id = 4, Name = "Person 4"},
new Person {Id = 5, Name = "Person 5"},
new Person {Id = 6, Name = "Person 6"},
new Person {Id = 7, Name = "Person 7"}
};
var output = (from ps1 in persons1
from ps2 in persons2
where ps1.Id == ps2.Id
select ps2.Name).ToList();
Person class
public class Person
{
public int Id { get; set; }
public string Name { get; set; }
}
If u wanna Select items of List from 2nd list:
MainList.Where(p => 2ndlist.Contains(p.columns from MainList )).ToList();
make single list and
var result = list.GroupBy(x => x.BillId).Where(x => x.Count() == 1).Select(x => x.First());
List<Car> cars = new List<Car>() { new Car() { Name = "Ford", Year = 1892, Website = "www.ford.us" },
new Car() { Name = "Jaguar", Year = 1892, Website = "www.jaguar.co.uk" },
new Car() { Name = "Honda", Year = 1892, Website = "www.honda.jp"} };
List<Factory> factories = new List<Factory>() { new Factory() { Name = "Ferrari", Website = "www.ferrari.it" },
new Factory() { Name = "Jaguar", Website = "www.jaguar.co.uk" },
new Factory() { Name = "BMW", Website = "www.bmw.de"} };
foreach (Car car in cars.Where(c => !factories.Any(f => f.Name == c.Name))) {
lblDebug.Text += car.Name;
}
Please find the table structure below:
Folderid parentFolderid Guid
1 0 1234
2 1 5678
3 2 9012
4 3 87697
5 7 4443
The requirement is if I pass folderId the function has to give me all the guids.
For example:If I pass 1 to the function, I should get first four Guids(parent and its children).
I have a function which returns all the guids as follows:
public List<Guid> Folders(int folderId)
{
// To get the folderids based on parentfolderid
var a = entity.Where(x => x.parentfolderId == folderId).FirstOrDefault();
return a;
}
I am able to get only up to one level of ids.
Is there any way to get parent, its children, grandchildren till the leaf?
If you are able to get that table to a class, check this out:
public class Entity
{
public int ID { get; set; }
public int ParentID { get; set; }
public string Name { get; set; }
public static List<Entity> GetTree(int ID, List<Entity> ListToSearch, bool First = true)
{
List<Entity> FilteredEntities = new List<Entity>();
FilteredEntities.AddRange(ListToSearch.Where<Entity>(x => x.ParentID == ID).ToList<Entity>());
List<Entity> Temp = new List<Entity>();
foreach (Entity current in FilteredEntities)
{
Temp.AddRange(GetTree(current.ID, ListToSearch, false));
}
FilteredEntities.AddRange(Temp);
if (First)
{
FilteredEntities.Add(ListToSearch.Where<Entity>(x => x.ID == ID).Single<Entity>());
}
return FilteredEntities;
}
}
Usage:
List<Entity> filteredEntities = Entity.GetTree(1, entities);
List<string> onlyTheNames = filteredEntities.Select<Entity, string>(x => x.Name).ToList<string>();
Regards
If you use this node class, you can write the code like this.
public class Folder
{
public int Id { get; set; }
public int? ParentId { get; set; }
public Guid SomeGuid { get; set; }
}
and and example of what possible is:
var list = new List<Folder>
{
new Folder {Id = 0, ParentId = null, SomeGuid = new Guid("0000b25b-8538-4b78-818a-9094507e0000") },
new Folder {Id = 1, ParentId = 0, SomeGuid = new Guid("1000b25b-8538-4b78-818a-9094507e0001") },
new Folder {Id = 2, ParentId = 1, SomeGuid = new Guid("2000b25b-8538-4b78-818a-9094507e0002") },
new Folder {Id = 3, ParentId = 1, SomeGuid = new Guid("3000b25b-8538-4b78-818a-9094507e0003") },
new Folder {Id = 4, ParentId = 2, SomeGuid = new Guid("4000b25b-8538-4b78-818a-9094507e0004") },
new Folder {Id = 5, ParentId = 3, SomeGuid = new Guid("5000b25b-8538-4b78-818a-9094507e0005") },
new Folder {Id = 6, ParentId = 0, SomeGuid = new Guid("6000b25b-8538-4b78-818a-9094507e0006") },
new Folder {Id = 7, ParentId = 4, SomeGuid = new Guid("7000b25b-8538-4b78-818a-9094507e0007") },
new Folder {Id = 8, ParentId = 3, SomeGuid = new Guid("8000b25b-8538-4b78-818a-9094507e0008") },
};
var rootNode = Node<Folder>.CreateTree(list, n => n.Id, n => n.ParentId).Single();
var firstChild = rootNode.Children.First(); // Id 1
var descendentsOfFirstChild = firstChild.Descendants; // All descendants of node 1