Automapper - How to map list into dictionary - c#

I've a list of records from DB like:
1;Order1;Name1;10,99
2;Order1;Name2;10,99
3;Order1;Name3;10,99
In the view I must list the names separated by comma:
Order1 contains products: Name1, Name2, Name3
Summary: 10,99
Now I take a list of items and I group it by Order1 and then I use for loop where I join names
foreach (var order in orders.GroupBy(f => f.OrderId))
{
var o = order.First();
o.Name = string.Join(", ", order.Select(f => f.Name));
items.Add(o); // this items are being mapped
}
at the end I map this list by automapper. I don't like this solution. Is it somehow possible to move this "name joining" do automapper?

Seems like you need to do the following (i not yet tested)
foreach (var order in orders.GroupBy(f => f.OrderId))
{
var strOrderId = order.Key;
var strNames = string.Join(", ", order.Select(f => f.Name));
Console.Writeline("{0} contains {1} ", strOrderId, strNames);
}

Related

My LINQ query is not ordering my dictionary

I have a Dictionary
Dictionary<string, List<Employee>> employees
that contains a list of employees. And I want to allow the user to display the list of employees in alphabetical order based on the state they are in.
Console.WriteLine($"If you would like to sort this list please enter one of the following choices..\n" +
$"'STATE', 'INCOME', 'ID', 'NAME', 'TAX' other wise enter any key.");
var sort = Console.ReadLine().ToUpper();
var employees = EmployeeRecord.employees;
List<Employee> sortedEmps = new List<Employee>();
if (sort.Contains("STATE"))
foreach (var list in employees.Values) {
var columnQuery = list.OrderBy(x => x.stateCode).ToList();
sortedEmps.AddRange(columnQuery);
}
}
//Print out the newly ordered list
foreach (Employee r in sortedEmps) {
Console.WriteLine($"ID: {r.iD} Name: {r.name} State: {r.stateCode} Income:{r.income} Tax Due: {r.taxDue}");
}
However, it still prints out the list without ordering it. How can I get it to order alphabetically by the state code?
Try sorting when you have all data merged.
if (sort.Contains("STATE")) {
foreach (var list in employees.Values) {
sortedEmps.AddRange(list);
}
sortedEmps = sortedEmps.OrderBy(x => x.stateCode).ToList();
}
Also you can shorten a little the code with SelectMany as #Robert Harvey suggested
if (sort.Contains("STATE")) {
sortedEmps = employees.Values
.SelectMany(x => x)
.ToList().OrderBy(o => o.stateCode).ToList();
}

how to find a property of a list and print it c#

Hi I have a list of grades which has students' names and their grades. I want to find the top student and print out his/her name and show it in the output. Here is my code
double maxgrade = grades.Max(t => t.value);
Console.WriteLine("the top student is : \n");
var topgrade = grades.Where(r => r.value == maxgrade);
Console.WriteLine(grades.Select(r=>r.studentinfo.name));
but it doesn't work. My list name contains grades with properties of studentinfo, courseinfo, value and unit of the grade. Can somebody help me?
The problem is that you are using select instead of FirstOrDefault. The Select returns a collection of items, even if only 1 item matches the predicate it is still a collection. When you print it you get the ToString() of IEnumerable<T> instead of what you actually want which is the value inside.
However, I think you can achieve what you are doing in a better way:
var name = grades.OrderByDescending(t => t.value)
.FirstOrDefault()?.studentinfo.name;
Console.WriteLine(name);
If have a few students with the highest grade and you want to print all those that have the highest grade:
var names = grades.GroupBy(item => item.value)
.OrderByDescending(group => group.Key)
.Select(group => group.Select(item => item.studentInfo.name))
.FirstOrDefault();
Console.WriteLine(string.Join(", ", names));
You have filtered using top grade so you need to print out from the filtered collection which is topgrade. So change the query
Console.WriteLine(topgrade.Select(r=>r.studentinfo.name).FirstOrDefault());
Using Zip:
var firstStudent = grades.Select(x => x.value).Zip(grades.Select(y => y.studentinfo.name),
(value, name) => new { Name = name, Value = value}).OrderBy(z => z.Value).ToList().First();
Console.WriteLine(firstStudent.Value + " " + firstStudent.Name);
You have to use FirstOrDefault() method afther calling the last Select(). The reason is because of the output of select method which is an IEnumerable<T>. For more information refer here.

How to find specific Elements in Lists which are part of Lists

My problem is::
I have a List of instances of a class "company"
each company contains a list of a class "Car" and an unique id
each car has a lot of specific data like "brand" an "model"
My task is to create a new list which contains all duplicate cars with the companys id who use them. In each "car" class is an object licensplateNO which is also unique. So to check only for duplicate instances of Cars is no option because each instance is different in the licenseplate property. My last Idea would be to do it the old fashioned way with a lot of loops comparing each property of each element with each other.
the result should look like this:
list duplicateCars:
Car1: BMW M4 used by Company B, Company F, Company X
Car2: Audi A3 used by Company B, Company D
Car3: VW Golf used by Company D, Company F .....
I think what you want can be achieved with the following.
var result = companies.SelectMany(
company => company.Cars.Select(car => new {Car = car, Company = company}))
.GroupBy(cc => new { cc.Car.Make, cc.Car.Model })
.Where(grp => grp.Count() > 1)
.Select(grp => new
{
grp.Key.Make,
grp.Key.Model,
Companies = string.Join(", ", grp.Select(cc => cc.Company.CompanyName))
});
First this selects all the companies and their cars, then it groups by the car's make and model, then it filters out the groups with only one type of car, and finally it selects the make and model of each unique type of car and creates a comma separated string of the company names. You may need to change the code to work with the specific names of your class properties, or to change exactly what properties of the car you want to group on.
Or alternatively you can use query syntax
var result = from company in compaines
from car in company.Cars
group new { Company = company, Car = car } by new { car.Make, car.Model }
into grp
where grp.Count() > 1
select new
{
grp.Key.Make,
grp.Key.Model,
Companies = string.Join(", ", grp.Select(cc => cc.Company.CompanyName))
};
I suggest breaking up your task into steps:
Pair a car type (make and model) with a company and compile a master list of these.
Group these pairs by the Car instead of the company
Select only the groups with multiple companies (you might need to check distinct companies if you have duplicate entries in your original data)
You now have a Collection of Car-List<Company> groupings. Print it or whatever
var carDealerPairs = dealers.SelectMany( d => d.Cars.Select(car => new {Car = car, Dealer = d}));
var groupsOfCars = carDealerPairs.GroupBy(pair => new {Make = pair.Car.Make, Model = pair.Car.Model});
var groupsWithDuplicates = groupsOfCars.Where(grp => grp.Count() > 1);
foreach (var grp in groupsWithDuplicates)
{
var car = grp.Key;
var companies = grp.Select(c => c.Dealer);
//do whatever
}
DotNetFiddle

Form a list of distinct words from set of repeating words lists in c#

I have a model:
public class CompanyModel1
{
public string compnName1 { get; set; }
public string compnKeyProcesses1 { get; set; }
}
then I form a list:
List<CompanyModel1> companies1 = new List<CompanyModel1>();
If I access its values:
var newpairs = companies1.Select(x => new { Name = x.compnName1, Processes = x.compnKeyProcesses1 });
foreach (var item in newpairs)
{
string CName = item.Name;
Process = item.Processes;
}
I will get value like:
CName = "name1"
Process = "Casting, Casting, Casting, Welding, brazing & soldering"
and
CName = "name2"
Process = "Casting, Welding, Casting, Forming & Forging, Moulding"
etc.
Now I want to form a list of distinct Process and count number of them, how many time each of them have by different name.
For example with these two above, I have to form a list like following:
"Casting, Welding, brazing & soldering, Forming & Forging, Moulding"
and if I count there will be: 5 distinct Processes; frequency of them by each name:
"Casting" appears in 2 names
"Welding" appears in 2 names
"brazing & soldering" appears in 1 names
"Forming & Forging" appears in 1 names
"Moulding" appears in 1 names
I am thinking of Linq can help with this problem, may be something like this:
var list= Process
.SelectMany(u => u.Split(new string[] { ", " }, StringSplitOptions.None))
.GroupBy(s => s)
.ToDictionary(g => g.Key, g => g.Count());
var numberOfProcess = list.Count;
var numberOfNameWithProcessOne = frequency["Process1"];
But how could I put that in the foreach loop and apply for all the names and processes that I have and get the result I want?
var processes = companies1.SelectMany(
c => c.compnKeyProcesses1.Split(new char[] { ',' }).Select(s => s.Trim()).Distinct())
.GroupBy(s => s).ToDictionary(g => g.Key, g => g.Count());
foreach(var process in processes)
{
Console.WriteLine("\"{0}\" appears in {1} names", process.Key, process.Value);
}
This selects only distinct processes from each individual company, and then creates all master list using SelectMany to store the correct number of unique occurrences for every process. Then we just count the occurrences of each process in the final list, and put them into a dictionary of process=>count.
EDIT:
Here is another solution that groups the data in a dictionary, to allow showing the associated companies with each process. The dictionary is from Process Names -> List of Company Names.
Func<string, IEnumerable<string>> stringToListConverter = s => s.Split(new char[] { ',' }).Select(ss => ss.Trim());
var companiesDict = companies1.ToDictionary(c => c.compnName1, c => stringToListConverter(c.compnKeyProcesses1).Distinct());
var processesAll = companies1.SelectMany(c => stringToListConverter(c.compnKeyProcesses1)).Distinct();
var processesToNames = processesAll.ToDictionary(s => s, s => companiesDict.Where(d => d.Value.Contains(s)).Select(d => d.Key).ToList());
foreach(var processToName in processesToNames)
{
List<string> companyNames = processToName.Value;
Console.WriteLine("\"{0}\" appears in {1} names : {2}", processToName.Key, companyNames.Count, String.Join(", ", companyNames));
}
I've saved the stringToListConverter Func delegate to convert the process string into a list, and used that delegate in two of the queries.
This query would be more readable if the CompanyModel1 class stored the compnKeyProcesses1 field as a List<string> instead of just one big string. That way you could instantly query the list instead of having the split, select, and trim every time.

LINQ, Combine Items with a similar value

Assuming I had a collection like this..
var list = new List<Item>
{
new Item
{
Name = "Software",
Price = 100
},
new Item
{
Name = "Software",
Price = 200
},
new Item
{
Name = "Hardware",
Price = 100
}
};
And the 'Names' are not going to be known, I want to write a LINQ query that will return a list of everything with a matching name. I cannot use "Select", because the names, again, are not known at design time.
Any ideas?
I'm not entirely sure whether you want to filter, or group the results.
If you want to filter, you can use Where with a runtime-supplied name:
string nameToFind = GetTheNameToFind(); // Can come from user, config, etc
var matches = list.Where(item => item.Name == nameToFind);
If you want to group by all of the names (ie: have 2 software + 1 hardware element), you could use Enumerable.GroupBy:
var groups = list.GroupBy(item => item.Name);
foreach(var group in groups)
{
Console.WriteLine("Group {0}:", group.Key);
foreach(var item in group)
Console.WriteLine(" Item: {0} - {1}", item.Name, item.Price);
}
Are you looking for this? You can use Where method to filter enumerable.
name variable can be defined at runtime.
string name = "Software";
List<Item> newList = list.Where(item => item.Name == name).ToList();

Categories

Resources