How can I insert a sequential number into a field using LINQ? - c#

I have the following code that I am using to put data into a relational table using Entity Framework:
public IList<Objective> createObjectives()
{
var objectiveNames = new[]
{
"Objective 1",
"Objective 2",
"Objective 3",
"Objective 4",
"Objective 5",
"Objective 6",
"Objective 7",
"Objective 8"
};
var objectives = objectiveNames.Select(o => new Objective
{
ObjectiveSeq = ??,
Name = o,
Description = o + " Description",
ModifiedDate = DateTime.Now
}
);
return objectives.ToList();
}
I have a new field in my table name ObjectiveSeq. How can I modify my LINQ to insert a sequential number in that field starting from 1.

var objectives = objectiveNames.Select((o, index) => new Objective
{
ObjectiveSeq = index,
Name = o,
Description = o + " Description",
ModifiedDate = DateTime.Now
}
);

There's an overload to the Select function. You can find it here.
Enumerable.Select<TSource, TResult> Method (IEnumerable<TSource>, Func<TSource, Int32, TResult>)
Take a look at the sample shown in the page.
string[] fruits = { "apple", "banana", "mango", "orange", "passionfruit", "grape" };
var query = fruits.Select((fruit, index) => new { index, str = fruit });
foreach (var obj in query)
{
Console.WriteLine("{0}", obj);
}
You can see that we are using (fruit, index). You are selecting both the element and an index.
The output will be
{ index = 0, str = apple }
{ index = 1, str = banana }
{ index = 2, str = mango }
{ index = 3, str = orange }
{ index = 4, str = passionfruit }
{ index = 5, str = grape }

Related

How to make one collection using three collections?

I want to make one collection of three according to certain conditions (with LINQ). let's say I have a Class:
class Collection
{
public int id;
public string name;
public double weight;
}
Then I'm creating collections:
List<Collection> collection1 = new()
{
new Collection() { id = 11, name = "Abraham 1", weight = 1.1 },
new Collection() { id = 12, name = "Abraham 2", weight = 1.2 },
new Collection() { id = 13, name = "Abraham 3", weight = 1.3 },
};
List<Collection> collection2 = new()
{
new Collection() { id = 21, name = "Bill 1", weight = 2.1 },
new Collection() { id = 22, name = "Bill 2", weight = 2.2 },
new Collection() { id = 23, name = "Bill 3", weight = 2.3 },
};
List<Collection> collection3 = new()
{
new Collection() { id = 31, name = "David 1", weight = 3.1 },
new Collection() { id = 32, name = "David 2", weight = 3.2 },
new Collection() { id = 33, name = "David 3", weight = 3.3 },
};
TODO 1. Condition: get 1st column from 1st collection, 2nd column from 2nd collection, 3rd column from 3rd column. result should be:
{
new Collection() { id = 11, name = "Bill 1", weight = 3.1 },
new Collection() { id = 12, name = "Bill 2", weight = 3.2 },
new Collection() { id = 13, name = "Bill 3", weight = 3.1 }
}
TODO 2. Second case condition: get first elements from columns of all collections. result should be:
{
new Collection() { id = 11, name = "Abraham 1", weight = 1.1 },
new Collection() { id = 21, name = "Bill 1", weight = 2.1 },
new Collection() { id = 31, name = "David 1", weight = 3.1 }
}
Please help.
Using C# 10 and .Net 6, just use Enumerable.Zip:
var todo1 = collection1.Zip(collection2, collection3)
.Select(t => new Collection { id = t.First.id, name = t.Second.name, weight = t.Third.weight })
.ToList();
var todo2 = collection1.Zip(collection2, collection3)
.Select(t => new List<Collection> { t.First, t.Second, t.Third })
.First();
If you don't have the three argument Zip that returns a tuple, just roll your own, e.g. for Todo1:
var td1 = collection1.Zip(collection2, (c1, c2) => (c1, c2))
.Zip(collection3, (t12, c3) => (First: t12.c1, Second: t12.c2, Third: c3))
.Select(t => new Collection { id = t.First.id, name = t.Second.name, weight = t.Third.weight })
.ToList();
If you want to merge multiple collections into one collection using LINQ then do this:
List<Collection> result = collection1.Concat(collection2).OrderBy(x => x.id).ToList();

add all values to a list of list from a list

I have a list of type class abc
public class abc
{
public int count;
public string country;
}
The list can have values like
Count: 1 - country: US Count: 2 - country: US Count: 3 -
country: IND Count: 4 - country: UK Count: 5 - country: UK
Now I want to put this list into a list of lists where it should be segregated based on countries.
My new list of lists should look like this
Count: 1 - country: US Count: 2 - country: US
Count: 3 - country: IND
Count: 4 - country: UK Count: 5 - country: UK
The count can have any integer and the country can have any string.
Is there any easy way to do this?
You can use GroupBy and select afterwards each group into a separate list:
List<abc> mylist = new List<abc>()
{
new abc{count = 1, country = "US"},
new abc{count = 2, country = "US"},
new abc{count = 3, country = "IND"},
new abc{count = 4, country = "UK"},
new abc{count = 5, country = "UK"},
};
List<List<abc>> result = mylist.GroupBy(x => x.country).Select(y => y.ToList()).ToList();
this way you get a list containing 3 other lists
Implement it like this:
List<abc> list = new List<abc>()
{
new abc() {country = "US", count = 1},
new abc() {country = "US", count = 2},
new abc() {country = "IND", count = 3},
new abc() {country = "UK", count = 4},
new abc() {country = "UK", count = 5}
};
Dictionary<string,List<abc>> dictionary = new Dictionary<string, List<abc>>();
foreach (var item in list)
{
if(!dictionary.TryGetValue(item.country,out var l))
{
l = new List<abc>();
dictionary.Add(item.country,l);
}
l.Add(item);
}
List<List<abc>> result = dictionary.Values.ToList();
you can do like this.
List<abc> ls = new List<abc>();
ls.Add(new abc() { count = 1, country = "US" });
ls.Add(new abc() { count = 2, country = "US" });
ls.Add(new abc() { count = 3, country = "IND" });
ls.Add(new abc() { count = 4, country = "UK" });
ls.Add(new abc() { count = 5, country = "UK" });
List<List<abc>> listOfList = new List<List<abc>>();
foreach (var group in ls.GroupBy(x => x.country))
{
List<abc> list = new List<abc>();
foreach (var item in group)
{
list.Add(new abc() { count = item.count, country = item.country });
}
listOfList.Add(list);
}
LINQ
List<List<abc>> listOfList = new List<List<abc>>();
foreach (var (group, list) in from item in ls.GroupBy(x => x.country)
let temp = new List<abc>()
select (item, temp))
{
foreach (var item2 in group)
{
list.Add(new abc() { count = item2.count, country = item2.country });
}
listOfList.Add(list);
}
Like many already answered, you could group your list by the countryString. However I personally would prefer to add it into a dictionary, so the access would be much easier to understand.
List<abc> myList = new List<abc>()
{
new abc{count = 1, country = "US"},
new abc{count = 2, country = "US"},
new abc{count = 3, country = "IND"},
new abc{count = 4, country = "UK"},
new abc{count = 5, country = "UK"},
};
You could as mentioned just group them:
var groupedLists = myList.GroupBy(x => x.country).Select(y => y.ToList()).ToList();
or you can make a dictionary out of it:
var myDictionary = myList.Select(item => item.country).Distinct().ToDictionary(country => country, country => myList.Where(item => item.country == country).ToList());
Now having the dictionary, you could access the specific list by the key (country). For example:
myDictionary["US"]; //would give you all items with the country "US"
It is up to you to chose whatever you would like to use. Just be aware that if you use the dictionary, you need to handle the possible keyNotFoundException
The easiest way to do this is with Linq.
You can use .GroupBy() to create groupings based on a properties value - in this case the Country.
In this example the .Select() statement uses a named tuple to make the data a bit more readable.
using System.Collections.Generic;
using System.Linq;
var data = new List<Abc>()
{
new()
{
Count = 1,
Country = "UK"
},
new()
{
Count = 2,
Country = "UK"
},
new()
{
Count = 3,
Country = "US"
}
};
var groupedData = data
.GroupBy(x => x.Country)
.Select(x => (Country: x.Key, Data: x.ToList()))
.ToList();
A way to consume and use this list of lists would be like so:
foreach (var (country, groupData) in groupedData)
{
var groupDataString = string.Join(" ", groupData.Select(x => x.Count));
Console.WriteLine($"{country}: {groupDataString}");
}
Example output looks like:
UK: 1 2
US: 3

At least one object must implement IComparable error in linq query

var pairs = new [] { new { id = 1, name = "ram", dept = "IT", sal = "3000" }, new { id = 2, name = "ramesh", dept = "IT", sal = "5000" }, new { id = 3, name = "rahesh", dept = "NONIT", sal = "2000" },
new { id = 5, name = "rash", dept = "NONIT", sal = "7000" } };
var query = from stud in pairs
where (stud.name.StartsWith("r") && stud.id % 2 != 0)
//orderby stud.sal descending
group stud by stud.dept into grps
select new { Values = grps, Key = grps.Key, maxsal=grps.Max() };
////select new { id = stud.id };
foreach (dynamic result in query)
{
Console.WriteLine(result.Key);
Console.WriteLine(result.maxsal);
foreach (dynamic result2 in result.Values)
{
Console.WriteLine(result2.id + "," + result2.sal);
}
}
Console.Read();
I am getting the error "At least one object must implement IComparable.", can someone explain me why iam I getting this error ?
You are calling grps.Max() to get maximnum item in group. Your anonymous objects are not comparable. How Linq will know which one is maximum from them? Should it use id property for comparison, or name?
I believe you want to select max salary:
maxsal = grps.Max(s => Int32.Parse(s.sal))

merge 2 complex lists in c#

I am programming in silverlight (c# .net)
lets say I have a list of type "data"
public class data
{
public string QUOTE_ID { get; set; }
public string EVENT_ACTION_CD { get; set; }
public string CUSTOMER_NAME { get; set; }
public string ADAPTIV_CODE { get; set; }
}
the problem is some of the data comes from 1 database and the other data comes from another, so right now i get the data in 2 steps - so i have something like this (using random numbers):
input1 = new List<data> //data return from database 1
//(the data is actually returned as a datable which i convert to a list
//to put to a datagrid, but the end result is shown below)
{
new data { QUOTE_ID = "1", EVENT_ACTION_CD = "2"},
new Project { QUOTE_ID = "2", EVENT_ACTION_CD = "4"},
new Project { QUOTE_ID = "3", EVENT_ACTION_CD = "5"}
};
input2 = new List<data> //data return from database 2
{
new data { QUOTE_ID = "1", CUSTOMER_NAME = "2", ADAPTIV_CODE ="5"},
new Project { QUOTE_ID = "2", CUSTOMER_NAME = "4", ADAPTIV_CODE = "5"},
new Project { QUOTE_ID = "3", CUSTOMER_NAME = "5", ADAPTIV_CODE = "7"}
};
so i should have 2 lists like
input1:
(1, 2, null, null
2, 4, null, null
3, 5, null, null)
and
input2:
(1, null, 2, 5
2, null, 4, 5
3. null, 5, 7)
how do i join them together to form one input list to become
(1, 2, 2, 5
2, 4, 4, 5
3, 5, 5, 7)
Use linq with a join operator.
See http://code.msdn.microsoft.com/101-LINQ-Samples-3fb9811b
var resultList = (from item in input1
join item2 in input2 on item2.QUOTE_ID equals input2.QUOTE_ID
let item.CUSTOMER_NAME = item2.CUSTOMER_NAME
let item.ADAPTIV_CODE = item2.ADAPTIV_CODE
select item).ToList();
A normal for loop would work for you:
for(int i = 0; i < input1.Count; i++){
if(input1[i].QUOTE_ID == null) input1[i].QUOTE_ID = input2[i].QUOTE_ID;
if(input1[i].EVENT_ACTION_CD == null) input1[i].EVENT_ACTION_CD = input2[i].EVENT_ACTION_CD;
if(input1[i].CUSTOMER_NAME == null) input1[i].CUSTOMER_NAME = input2[i].CUSTOMER_NAME;
if(input1[i].ADAPTIV_CODE == null) input1[i].ADAPTIV_CODE = input2[i].ADAPTIV_CODE;
}
The result will be saved into the input1. The code also supposes input1 and input2 have the same Count.
var input3 = input1.Join(
input2,
d1 => d1.QUOTE_ID,
d2 => d2.QUOTE_ID,
(d1, d2) => new data() {
QUOTE_ID = d1.QUOTE_ID,
EVENT_ACTION_CD = d1.EVENT_ACTION_CD,
CUSTOMER_NAME = d2.CUSTOMER_NAME,
ADAPTIV_CODE = d2.ADAPTIV_CODE
}
);

LINQ C# - Combining multiple groups

LINQ Groupby query creates a new group for each unique key. I would like to combine multiple groups into a single group based on the key value.
e.g.
var customersData = new[]
{
new { id = 1, company = "ABC" },
new { id = 2, company = "AAA" },
new { id = 3, company = "ABCD" },
new { id = 4, company = "XYZ" },
new { id = 5, company = "X.Y.Z." },
new { id = 6, company = "QQQ" },
};
var groups = from d in customersData
group d by d.company;
Let's say I want ABC, AAA, and ABCD in the same group, and XYZ, X.Y.Z. in the same group.
Is there anyway to achieve this through LINQ queries?
You will need to use the overload of GroupBy that takes an IEqualityComparer.
var groups = customersData.GroupBy(k => k.company, new KeyComparer());
where KeyComparer could look like
public class KeyComparer : IEqualityComparer
{
public bool Equals(string x, string y)
{
// put your comparison logic here
}
public int GetHashCode(string obj)
{
// same comparison logic here
}
}
You can comparer the strings any way you like in the Equals method of KeyComparer.
EDIT:
You also need to make sure that the implementation of GetHashCode obeys the same rules as the Equals method. For example if you just removed the "." and replaced with "" as in other answers you need to do it in both methods like this
public class KeyComparer : IEqualityComparer
{
public bool Equals(string x, string y)
{
return x.Replace(".", "") == y.Replace(".", "");
}
public int GetHashCode(string obj)
{
return obj.Replace(".", "").GetHashCode();
}
}
I am assuming the following:
You meant to have quotes surrounding the company "names" (as below).
Your problem is simply solved by removing the '.'s from each company name.
If these assumptions are correct, the solution is simply the following:
var customersData = new[] {
new { id = 1, company = "ABC" },
new { id = 2, company = "A.B.C." },
new { id = 3, company = "A.B.C." },
new { id = 4, company = "XYZ" },
new { id = 5, company = "X.Y.Z." },
new { id = 6, company = "QQQ" },
};
var groups = from d in customersData
group d by d.company.Replace(".", "");
If these assumptions are not correct, please clarify and I can help work closer to a solution.
var groups = from d in customersData
group d by d.company.Replace(".", "");
public void int GetId(Company c)
{
int result = //whatever you want
return result;
}
then later:
var groups = from d in customersData
group d by GetId(d.company);
I think this is what you want:
var customersData = new[]
{
new { id = 1, company = "ABC" },
new { id = 2, company = "AAA" },
new { id = 3, company = "ABCD" },
new { id = 4, company = "XYZ" },
new { id = 5, company = "X.Y.Z." },
new { id = 6, company = "QQQ" },
};
var groups = from d in customersData
group d by d.company[0];
foreach (var group in groups)
{
Console.WriteLine("Group " + group.Key);
foreach (var item in group)
{
Console.WriteLine("Item " + item.company);
}
}
Console.ReadLine();

Categories