I an intermediate C# develop. I am trying to implement some methods in my program. But it's been giving sleepless nights. E.g
NB: I already declared the class properties ahead.
Employee employe = new Employee(){
ID = 111,
Name = "Eric Trump",
Gender = "Male",
Salary = 900000
};
Employee employe2 = new Employee()
{
ID = 112,
Name = "Ayo",
Gender = "Female",
Salary = 8900
};
List<Employee> listemp = new List<Employee>();
listemp.Add(employe);
listemp.Add(employe2);
How to i use the Find, FindAll() or FindLast()?
You can do that by passing a Predicate<T> delegate to Find, FindLast or FindAll methods
List<Employee> listemp = new List<Employee>();
listemp.Add(employe);
listemp.Add(employe2);
var result = listemp.FindLast(e => e.ID == 112); //or listemp.Find(e => e.ID == 112)
e => e.ID == 112 is called lambda expression, it's just a more convenient way to specify an anonymous delegate, you can find more details at Delegates and lambdas
Just use lambda-expressions:
List<string> lists = new List<string>()
{
"1", "2", "3"
};
var all = lists.FindAll(s => s == "1");
Read more about Find all here.
UPDATE:
Lambda-expression is a shorter way to represent anonymous methods. So you can use them like that:
List<Employee> employees = new List<Employee>()
{
new Employee(){
Id = 111,
Name = "Eric Trump",
Gender = "Male",
Salary = 900000
},
new Employee(){
Id = 112,
Name = "Ayo",
Gender = "Female",
Salary = 8900
}
};
var findAll = employees.FindAll(s => s.Id == 111);
var findLast = employees.FindLast(s => s.Id == 111);
var find = employees.Find(s => s.Id == 111);
Related
IList<Student> studentList = new List<Student>() {
new Student() { StudentID = 1, StudentName = "John", Age = 18, StandardID = 1 } ,
new Student() { StudentID = 2, StudentName = "Steve", Age = 21, StandardID = 1 } ,
new Student() { StudentID = 3, StudentName = "Bill", Age = 18, StandardID = 2 } ,
new Student() { StudentID = 4, StudentName = "Ram" , Age = 20, StandardID = 2 } ,
new Student() { StudentID = 5, StudentName = "Ron" , Age = 21 }
};
IList<Standard> standardList = new List<Standard>() {
new Standard(){ StandardID = 1, StandardName="Standard 1"},
new Standard(){ StandardID = 2, StandardName="Standard 2"},
new Standard(){ StandardID = 3, StandardName="Standard 3"}
};
var studentsWithStandard = from stad in standardList
join s in studentList
on stad.StandardID equals s.StandardID
into sg
from std_grp in sg
orderby stad.StandardName, std_grp.StudentName
select new {
StudentName = std_grp.StudentName,
StandardName = stad.StandardName
};
foreach (var group in studentsWithStandard)
{
Console.WriteLine("{0} is in {1}", group.StudentName, group.StandardName);
}
i tried. my code is following.
var studentsWithStandard = standardList.GroupJoin(studentList, stand => stand.StandardID, s => s.StandardID,
(stand, students) => new {StandardName = stand.StandardName, studentGroup = students}).OrderBy(an => an.StandardName);
output will be like this:
John is in Standard 1
Steve is in Standard 1
Bill is in Standard 2
Ram is in Standard 2
i got it from http://www.tutorialsteacher.com/codeeditor?cid=cs-JUmITE
Thanks in advance.
In my experience join is the one place where query syntax is more readable than lambda syntax, but regardless...
I would highly recommend reading Jon Skeet's excellent book C# In Depth. The chapters on LINQ give very clear explanations of what various query syntaxes translate to. https://www.manning.com/books/c-sharp-in-depth-third-edition
A join expression that only has one from will translate to the Join method, not GroupJoin. GroupJoin is used when you have two froms before the join.
You would want this to do an inner join:
standardList
.Join(studentList,
stad => stad.StandardID,
s => s.StandardID,
(stad, s) => new { Standard = stad, Student = s })
.OrderBy(x => x.Standard.StandardName)
.ThenBy(x => x.Student.StudentName)
You can translate the query like this:
var ans = standardList.Join(studentList, stad => stad.StandardID, s => s.StandardID, (stad, s) => new { stad, s })
.OrderBy(stads => stads.stad.StandardName).ThenBy(stads => stads.s.StudentName)
.Select(stads => new { stads.s.StudentName, stads.stad.StandardName });
Note that #JamesFaix's answer provides a more efficient less literal version that combines the Join and Select.
Which is actually the query comprehension version without into which isn't needed for your query:
var studentsWithStandard = from stad in standardList
join s in studentList on stad.StandardID equals s.StandardID
orderby stad.StandardName, s.StudentName
select new {
StudentName = s.StudentName,
StandardName = stad.StandardName
};
Note a strict translation of your query would involve GroupJoin/SelectMany but it isn't necessary since you aren't try to do a left join:
var ans2 = standardList.GroupJoin(studentList, stad => stad.StandardID, s => s.StandardID, (stad, sg) => new { stad, sg })
.SelectMany(stadsg => stadsg.sg.Select(s => new { stadsg.stad, s }))
.OrderBy(stads => stads.stad.StandardName).ThenBy(stads => stads.s.StudentName)
.Select(stads => new { stads.s.StudentName, stads.stad.StandardName });
I have two rows which have all the data same except one column.
I want to show only one row on the UI but one row which has different data should be shown as comma seperated values.
Sample Data
PricingID Name Age Group
1 abc 56 P1
1 abc 56 P2
Output should be :
PricingID Name Age Group
1 abc 56 P1,P2
I am using this approach but it is not working , it gives me two rows only but data i am able to concatenate with comma.
List<PricingDetailExtended> pricingDetailExtendeds = _storedProcedures.GetPricingAssignment(pricingScenarioName, regionCode, productCode, stateCode, UserId, PricingId).ToList();
var pricngtemp = pricingDetailExtendeds.Select(e => new
{
PricingID = e.PricingID,
OpportunityID = e.OpportunityID,
ProductName = e.ProductName,
ProductCD = e.ProductCD
});
pricingDetailExtendeds.ForEach(e=>
{
e.ProductCD = string.Join(",",string.Join(",", (pricngtemp.ToList().Where(p => p.PricingID == e.PricingID).Select(k => k.ProductCD).ToArray())).Split(',').Distinct().ToArray());
e.OpportunityID =string.Join(",", string.Join(",", (pricngtemp.ToList().Where(p => p.PricingID == e.PricingID).Select(k => k.OpportunityID).ToArray())).Split(',').Distinct().ToArray());
e.ProductName =string.Join(",", string.Join(",", (pricngtemp.ToList().Where(p => p.PricingID == e.PricingID).Select(k => k.ProductName).ToArray())).Split(',').Distinct().ToArray());
}
);
// pricingDetailExtendeds = GetUniquePricingList(pricingDetailExtendeds);
return pricingDetailExtendeds.Distinct().AsEnumerable();
Any body can suggest me better approach and how to fix this issue ?
Any help is appreciated.
You want to use the GroupBy linq function.
I then use the String.Join function to make the groups comma seperated.
So something like this:
var pricingDetailExtendeds = new[]
{
new
{
PricingID = 1,
Name = "abc",
Age = 56,
Group = "P1"
},
new
{
PricingID = 1,
Name = "abc",
Age = 56,
Group = "P2"
}
};
var pricngtemp =
pricingDetailExtendeds.GroupBy(pde => new {pde.PricingID, pde.Name, pde.Age})
.Select(g => new {g.Key, TheGroups = String.Join(",", g.Select(s => s.Group))}).ToList();
You can easily extrapolate this to the other fields.
To return the PricingDetailExtended, the just create it in the select. So something like this
.Select(g => new PricingDetailExtended {
PricingID = g.Key.PricingId,
TheGroups = String.Join(",", g.Select(s => s.Group))
}).ToList();
You won't have the field TheGroups though, so just replace that field with the proper one.
An example of what I was describing in my comment would be something along the lines of the following. I would expect this to be moved into a helper function.
List<PriceDetail> list = new List<PriceDetail>
{
new PriceDetail {Id = 1, Age = 56, Name = "abc", group = "P1"},
new PriceDetail {Id = 1, Age = 56, Name = "abc", group = "P2"},
new PriceDetail {Id = 2, Age = 56, Name = "abc", group = "P1"}
};
Dictionary<PriceDetailKey, StringBuilder> group = new Dictionary<PriceDetailKey, StringBuilder>();
for (int i = 0; i < list.Count; ++i)
{
var key = new PriceDetailKey { Id = list[i].Id, Age = list[i].Age, Name = list[i].Name };
if (group.ContainsKey(key))
{
group[key].Append(",");
group[key].Append(list[i].group);
}
else
{
group[key] = new StringBuilder();
group[key].Append(list[i].group);
}
}
List<PriceDetail> retList = new List<PriceDetail>();
foreach (KeyValuePair<PriceDetailKey, StringBuilder> kvp in group)
{
retList.Add(new PriceDetail{Age = kvp.Key.Age, Id = kvp.Key.Id, Name = kvp.Key.Name, group = kvp.Value.ToString()});
}
you could even convert the final loop into a LINQ expression like:
group.Select(kvp => new PriceDetail {Age = kvp.Key.Age, Id = kvp.Key.Id, Name = kvp.Key.Name, group = kvp.Value.ToString()});
Its worth noting you could do something similar without the overhead of constructing new objects if, for example, you wrote a custom equality comparer and used a list instead of dictionary. The upside of that is that when you were finished, it would be your return value without having to do another iteration.
There are several different ways to get the results. You could even do the grouping in SQL.
I would like to know if you can suggest me an efficient way to update a list of items in c#. Here is a generic example:
If CurrentList is
[ {Id: 154, Name: "George", Salary: 10 000}
{Id: 233, Name: "Alice", Salary: 10 000}]
And NewList is
[ {Id: 154, Name: "George", Salary: 25 000}
{Id: 234, Name: "Bob", Salary: 10 000}]
Then the result should be:
[{Id: 154, Name: "George", Salary: 25 000}
{Id: 234, Name: "Bob", Salary: 10 000} ]
I don't want just to clear the first one and use the values from the second one, but want to update the ones with the same ID, remove the ones that have been deleted and add any new ones.
Thanks in advance.
I would do something like this: (for ordinairy lists)
// the current list
var currentList = new List<Employee>();
currentList.Add(new Employee { Id = 154, Name = "George", Salary = 10000 });
currentList.Add(new Employee { Id = 233, Name = "Alice", Salary = 10000 });
// new list
var newList = new List<Employee>();
newList.Add(new Employee { Id = 154, Name = "George", Salary = 25000 });
newList.Add(new Employee { Id = 234, Name = "Bob", Salary = 10000 });
// clean up
foreach (var oldEmployee in currentList.ToArray())
if (!newList.Any(item => oldEmployee.Id == item.Id))
currentList.Remove(oldEmployee);
// check if the new item is found within the currentlist.
// If so? update it's values else add the object.
foreach (var newEmployee in newList)
{
var oldEmployee = currentList.FirstOrDefault(item => item.Id == newEmployee.Id);
if (oldEmployee == null)
{
// add
currentList.Add(newEmployee);
}
else
{
// modify
oldEmployee.Name = newEmployee.Name;
oldEmployee.Salary = newEmployee.Salary;
}
}
You can speed it up, using dictionaries, but that's not your question (for now)
You can do it with use of for loop and Linq expression:
for (int i = 0; i < NewList.Count; i++)
{
var record = CurrentList.FirstOrDefault(item => item.Id == NewList[i].Id);
if (record == null) { CurrentList.Add(NewList[i]); }
else { record.Id = NewList[i].Id; record.Name = NewList[i].Name; record.Salary = NewList[i].Salary; }
}
CurrentList.RemoveAll(item => NewList.FirstOrDefault(item2 => item2.Id == item.Id) == null);
Example of usage:
Example
A LINQ'y version wrapped in an extension method, could modified to be generic if 'Id' is on a interface of some sort.
The merge Action could potentially be a Merge() method on entity objects such as employee but I chose to use a delegate here .
public class Tests
{
[Test]
public void MergeSpike()
{
// the current list
var currentList = new List<Employee>();
currentList.Add(new Employee { Id = 154, Name = "George", Salary = 10000 });
currentList.Add(new Employee { Id = 233, Name = "Alice", Salary = 10000 });
// new list
var newList = new List<Employee>();
newList.Add(new Employee { Id = 154, Name = "George", Salary = 25000 });
newList.Add(new Employee { Id = 234, Name = "Bob", Salary = 30000 });
currentList.Merge(newList, (o, n) =>
{
if(o.Id != n.Id) throw new ArgumentOutOfRangeException("Attempt to merge on mismatched IDs");
o.Name = n.Name;
o.Salary = n.Salary;
});
Assert.That(currentList.Count(), Is.EqualTo(2));
Assert.That(currentList.First(c => c.Id == 154).Salary, Is.EqualTo(25000));
Assert.That(currentList.Any(c => c.Id == 233), Is.False);
Assert.That(currentList.First(c => c.Id == 234).Salary, Is.EqualTo(30000));
}
}
public class Employee
{
public int Id { get; set; }
public string Name { get; set; }
public int Salary { get; set; }
}
public static class EmployeeListExtensions
{
public static void Merge(this List<Employee> currentList, IEnumerable<Employee> newList, Action<Employee, Employee> merge)
{
// Updates
currentList.Where(e => newList.Any(n => n.Id == e.Id))
.ToList().ForEach(e => merge(e, newList.First(n1 => n1.Id == e.Id)));
// Deletes
var remove = currentList.Where(cl => newList.All(nl => cl.Id != nl.Id)).ToList();
currentList.RemoveAll(e => remove.Any(r => r.Id == e.Id));
// Inserts
currentList.AddRange(newList.Where(nl => currentList.Any(c => c.Id != nl.Id)));
}
}
I'm stuck on this problem where I need to do descending sort based on other list. l_lstNames need to update by age descending.
public class Test
{
public String Name;
public Int32 Age;
}
List<String> l_lstNames = new List<String> { "A1", "A3", "A2", "A4", "A0" };
List<Test> l_lstStudents = new List<Test>
{
new Test { Age = 33, Name = "A0" },
new Test { Age = 10, Name = "A1" },
new Test { Age = 50, Name = "A2" },
new Test { Age = 8, Name = "A3" },
new Test { Age = 25, Name = "A4" },
};
// Output
List<String> l_lstNames = new List<String> { "A2", "A0", "A4", "A1", "A3" };
Found few sames samples but not matching what I'm looking for. Thank you for help.
Create Dictionary<string, int> with Name to Age mapping and use it within order method:
var dict = students.ToDictionary(x => x.Name, x => x.Age);
var ordered = source.OrderByDescending(x => dict[x.Name]).ToList();
or you can just order students collection and then select Name only:
var ordered = students.OrderByDescending(x => x.Age)
.Select(x => x.Name)
.ToList();
If you just want the names in order descending:
var sorted = l_lstStudents // From the list of students
.OrderByDescending(l => l.Age) // with the oldest student first
.Select(s => s.Name) // give me just the names
.ToList(); // in a list!
I think this is what you are looking for
List<String> l_lstNames1 = (from student in l_lstStudents
where l_lstNames.Any(a => student.Name == a)
orderby student.Age descending
select student.Name ).ToList();
OR
List<String> l_lstNames2 = l_lstStudents.OrderByDescending(a => a.Age)
.Where(a => l_lstNames.Any(b => b == a.Name))
.Select(a => a.Name).ToList();
How do I count, group and sort the following list based on a persons money with linq?
Person[] names = { new Person{ Name = "Harris", Money = 100 },
new Person{ Name = "David", Money = 100 },
new Person{Name = "Harris", Money = 150},
new Person{Name = "Mike", Money = 100},
new Person{Name = "Mike", Money = 30},
new Person{Name = "Mike", Money = 20} };
The result would return:
Harris 250
Mike 150
David 100
var personMoney = names.GroupBy(x=>x.Name)
.Select(x=>new {Name = x.Key, AllMoney = x.Sum(y=>y.Money)})
.OrderByDescending(x=>x.AllMoney).ToList();
from p in names
group p by p.Name into g
order by g.Key
select new { Name = g.Key, Amount = g.Sum(o => o.Amount) }