Splitting an ordered list [duplicate] - c#

This question already has answers here:
Group by in LINQ
(11 answers)
Closed 4 years ago.
I am trying to create a sorted list of lists. Where the outer "layer" is sorted by the field BU. and the inner layer is sorted by JobNum. I have this method, and variables.
public List<string> ListSorter<T>(IEnumerable<T> records)where T :
IMapToCSVSource, new()
List<IEnumerable<T>> organizedRecords = new List<IEnumerable<T>>();
List<T> shortenedRecord = new List<T>();
Here I am trying to create a more concise object with only 3 specific fields instead of the possible 8 that comes with the records object. BU and JobNum are set within this method.
foreach (var record in records)
{
string businessUnit = "research"; //This would vary each loop, not constant as displayed
string JobNum = "test" //this would vary each loop, not constant as displayed
shortenedRecord.Add(new T()
{
Cost = record.Cost,
BU = businessUnit,
JobNum = jobNum
});
}
shortenedRecord.OrderBy(o => o.BU).ThenBy(n=>n.JobNum);
here, to my knowledge, now has all the records shortened and ordered by BU, then JobNum.
Now I want to Split this ordered list into sections of BU specific records and add it to organizedRecords. Such that each element of organizedRecords is a specific BU. How would I do this?
For example, say shortenedRecord is a list of 30 elements, but there is only a total of 5 unique BU values. I would like to order and SPLIT the list into their 5 respective BU values, and add it to organizedRecords.
such that:
organizedRecords[0] should be a list of 'corporate' records
organizedRecords[1] should be a list of 'research' records
where corporate and research are BU values.
I tried to explain as best I could. Thank you for any suggestions.

Thanks for suggestions, I toyed around a bit, and I found this to work as I needed it.
var query = shortenedRecord.GroupBy(p => p.BU).ToList();
foreach (var group in query)
{
var ordered = group.OrderBy(x => x.JobNum);
organizedRecords.Add(ordered);
}

Related

More efficient way of using LINQ to compare two items?

I am updating records on a SharePoint list based on data from a SQL database. Lets say my table looks something like this:
VendorNumber
ItemNumber
Descrpition
1001
1
abc
1001
2
def
1002
1
ghi
1002
3
jkl
There can be multiple keys in each table. I am trying to make a generic solution that will work for multiple different table structures. In the above example, VendorNumber and ItemNumber would be considered keys.
I am able to retrieve the SharePoint lists as c# List<Microsoft.SharePoint.Client.ListItem>
I need to search through the List to determine which individual ListItem corresponds to the current SQL datarow I am on. Since both ListItem and DataRow allow bracket notation to specify column names, this is pretty easy to do using LINQ if you only have one key column. What I need is a way to do this if I have anywhere from 1 key to N keys. I have found this solution but realize it is very inefficient. Is there a more efficient way of doing this?
List<string> keyFieldNames = new List<string>() { "VendorNumber", "ItemNumber" };
List<ListItem> itemList = MyFunction_GetSharePointItemList();
DataRow row = MyFunction_GetOneRow();
//this is the part I would like to make more efficient:
foreach (string key in keyFieldNames)
{
//this filters the list with each successive pass.
itemList = itemList.FindAll(item => item[key].ToString().Trim() == row[key].ToString().Trim());
}
Edited to Add: Here is a link to the ListItem class documentation:
Microsoft.SharePoint.Client.ListItem
While ListItem is not a DataTable object, its structure is very similar. I have intentionally designed it so that both the ListItem and my DataRow object will have the same number of columns and the same column names. This was done to make comparing them easier.
A quick optimization tip first:
Create a Dictionary<string, string> to use instead of row
List<string> keyFieldNames = new List<string>() { "VendorNumber", "ItemNumber" };
DataRow row = MyFunction_GetOneRow();
var rowData = keyFieldNames.ToDictionary(name=>row[name].ToString().Trim());
foreach (string key in keyFieldNames)
{
itemList = itemList.FindAll(item => item[key].ToString().Trim() == rowData[key]);
}
This will avoid doing the ToString & Trim on the same records over & over. That's probably taking 1/3rd to 1/2 the time of the loop. (The comparison is fast compared to the string manipulation)
Beyond that, all I can think of is to use reflection to build a specific function, on the fly to handle the comparison. BUT, that would be a big effort, and I don't see it saving that much time. Basically, whatever you do, will still have to do the same basics: Lookup the values by key, and compare them. That's what's taking the majority of the time.
After I stopped looking for an answer, I stumbled across one. I have now realized that using a .Where is implemented using deferred execution. This means that even though the foreach loop iterates several times, the LINQ query executes all at once. This was the part I was struggling to wrap my head around.
My new sudo code:
List<string> keyFieldNames = new List<string>() { "VendorNumber", "ItemNumber" };
List<ListItem> itemList = MyFunction_GetSharePointItemList();
DataRow row = MyFunction_GetOneRow();
//this is the part I would like to make more efficient:
foreach (string key in keyFieldNames)
{
//this filters the list with each successive pass.
itemList = itemList.Where(item => item[key].ToString().Trim() == row[key].ToString().Trim());
}
I know that the .ToString().Trim() is still inefficient, I will address this at some point. But for now at least my mind can rest knowing that the LINQ executes all at once.

How to Compare two properties and then sort [duplicate]

This question already has answers here:
List<string> complex sorting
(5 answers)
Closed 6 years ago.
I have a list of strings in order I've set manually "1" "2" "5" "4" "3" etc.. I also have another class tied to a number of elements which contains various properties, one of which is an int OrderString
How do I re-arrange the order of the objects according to my list of strings.
list<string> L_string = new string { "1" "2" "4" "3" "5" "6" "7"}
Also a list of Items the that properties such as Name, Number, Date attached to them.
Assuming l_Item inherits from Products
var SortedMan =
l_Item.OrderBy(o=>o.number.ToString()).CompareTo(L_string)));
Something like that, but an actual working code.
So basically the amount of items in both will be the same. I need it to re arrange list of Items in order of how they are inside the L_string.
You can use this GenericComparer class implementation.
Use somehting like this
Array.Sort(YourArray, new GenericComparer());
Or use
Array.Sort(YourArray, new PropertyDescriptorComparer());
for property of class.
Assuming I_Item is a List<Product>:
var sortedList = new List<Product>();
foreach (var value in L_string)
{
sortedList.AddRange(I_Item.Where(x => x.number.ToString() == value));
}
Assuming that entries in L_string actually correspond to items in l_item, you can do something like this:
var sorted = l_item
.Where(item => L_string.Contains(item.number.ToString()))
.OrderBy(item => L_string.IndexOf(item.number.ToString()));
The Where method filters the collection and returns a new collection with all matching elements. OrderBy reorders the collection based on the item's index in the L_string collection.

How to merge 3 List items from on list and add them to another List? [duplicate]

This question already has answers here:
How can I join strings from one List<string> into another one? [closed]
(5 answers)
Closed 6 years ago.
I have 2 string Lists.
In the first List I have 30 or more entries.
For the second list, I need to merge 3 items and add them to list 2 as 1 item.
Here an example of what I mean:
List<string> dinosaurs = new List<string>();
dinosaurs.Add("Tyrannosaurus");
dinosaurs.Add("Amargasaurus");
dinosaurs.Add("Mamenchisaurus");
dinosaurs.Add("Deinonychus");
dinosaurs.Add("Compsognathus");
dinosaurs.Add("VelociRaptor")
List<string> dinosaursmerged = new List<string>();
Inside this list there are two items, which contain:
item1 = "Tyrannosaurus; Amargasaurus; Mamenchisaurus"
item2 = "Mamenchisaurus; Mamenchisaurus; VelociRaptor"
I tried it with the stringbuilder and with concat but had no success.
Any help or advice would be great - thanks for your time.
If you want to group your first list in a second list with 3 elements joined together then you could write
List<string> merged = new List<string>();
for(int x = 0; x < dinosaurs.Count; x+=3)
merged.Add(string.Join(",", dinosaurs.Skip(x).Take(3)));
This will work also if the first list doesn't contain a number of elements multiple of 3. Of course the last element could be composed of 1, 2 or 3 elements from the first list.

Converting a list of lists into a single list using linq [duplicate]

This question already has answers here:
How to merge a list of lists with same type of items to a single list of items?
(4 answers)
Closed 8 years ago.
I am a list of lists with the same type of objects and I am trying to convert it to a single list with all the objects using linq.
How can I do this?
This is my current code:
var allTrackAreas =
_routables.Select(
routable =>
_centrifugeHelper.GetTrackAreasFromRoutable(routable, _trackAreaCutterParameters,
_allowedDestination.MatchedAreas[routable]))
.Where(area => area != null).ToList();
foreach (var testAction in _trackAreaCutterParameters.ConcurrentBagTestActions)
{
if (allTrackAreas.Any(areas => areas.Any(area => area.Id == testAction.TrackAreaId)))
{
currentActions.Add(testAction);
}
}
The variable allTrackAreas is a list of lists and I am using twice Any on it which is quite bad for efficiency. It would be much better if it was a simple list.
You can do:
var allTrackAreasCombined = allTrackAreas.SelectMany(t => t).ToList();
If you have list of list like this
list[0]
Records1[0]
Records2[1]
Records3[2]
list[1]
Records1[0]
Records2[1]
Records3[2]
so you can make all Records in single list like using this code
list<object> test = new list<object>();
foreach(object items in list)
{
foreach(object item in items)
{
test.add(item);
}
}
then in test you got all six records.
I hope this help you.

sorting List<string[]> by many columns

I have List which I would like to sort by many columns. For example, string[] has 5 elements (5 columns) and List has 10 elements (10 rows). For example I would like to start sorting by 1st column, then by 3rd and then by 4th.
How could it be done in the easiest way with C#?
I thought about such algorithm:
Delete values corresponding to those columns that I don't want to use for sorting
Find for each of columns that are left, the longest string that can be used to store their value
Change each row to string, where each cell occupies as many characters as there is maximum number of characters for the value for the given column
Assign int with index for each of those string values
Sort these string values
Sort the real data, with help of already sorted indices
But I think this algorithm is very bad. Could you suggest me any better way, if possible, that uses already existing features of C# and .NET?
List<string[]> list = .....
var newList = list.OrderBy(x => x[1]).ThenBy(x => x[3]).ThenBy(x => x[4]).ToList();
Something like this:
var rows = new List<string[]>();
var sortColumnIndex = 2;
rows.Sort((a, b) => return a[sortColumnIndex].CompareTo(b[sortColumnIndex]));
This will perform an in-place sort -- that is, it will sort the contents of the list.
Sorting on multiple columns is possible, but requires more logic in your comparer delegate.
If you're happy to create another collection, you can use the Linq approach given in another answer.
EDIT here's the multi-column, in-place sorting example:
var rows = new List<string[]>();
var sortColumnIndices = new[] { 1, 3, 4 };
rows.Sort((a, b) => {
for (var index in sortColumnIndices)
{
var result = a[index].CompareTo(b[index]);
if (result != 0)
return result;
}
return 0;
});

Categories