Multiple List Iteration - c#

I have (2) lists we shall call List A & List B which may be at different lengths. Each item has a contained parameter associated to it as an identifier, in this case we can call Comment. I need to iterate:
foreach (item a in A)
{
foreach (item b in B)
{
if (b.Comment == a.Comment)
{
send to a void to process: void(b,a);
Essentially, I need to process each item from one list to the other if they have the same identifier. Would a zip benefit in this case? From what I've laid out, logically I would like to loop for each item in List A, check each item in List B that has the same identifier "Comment", if yes then send the current a & b value into a function to process and continue to loop the rest of List A.

Rethink the collection type you are using.
If you had one of your lists as a dictionary, where the key is the comment, you would only have to iterate one of the lists, and then check if your dictionary contains that.
If comment is string, and item is a type.
Dictionary<string, item>
Using LINQ it's easy to generate a dictionary: https://learn.microsoft.com/en-us/dotnet/api/system.linq.enumerable.todictionary
Of course you can't have multiple items with the same key in the dictionary. If there is no unique constraint on comment, your dictionary could look like this
Dictionary<string, List<item>>
I won't go into more detail with the code without full context, but I think you get the point.

After some research I've went the Cartesian Product route obtaining each pair's respective [0] and [1] elements
var Fruits =
from apple in ListA
from Banana in ListB
select new[] {apple, Banana};
then went on to break down sending Smoothie(Fruits[0],Fruits[1])

Related

How to Update a list with another list efficiently C#

I have two lists that have object elements, one big list let's call it List1 and another small list List2.
I need to update values in List1 with values in List2 based on a condition that is defined in a function that returns a boolean based on the values in the objects.
I have come up with the following implementation which is really taking a lot of time for larger lists.
function to check whether an item will be updated
private static bool CheckMatch(Item item1, Item item2) {
//do some stuff here and return a boolean
}
query I'm using to update the items
In the snippet below, I need to update List1(larger list) with some values in List2(small list)
foreach(var item1 in List1)
{
var matchingItems = List2.Where(item2 => CheckMatch(item1, item2));
if (matchingItems.Any())
{
item1.IsExclude = matchingItems.First().IsExcluded;
item1.IsInclude = matchingItems.First().IsIncluded;
item1.Category = matchingItems.First().Category;
}
}
I'm hoping I will get a solution that is much better than this. I also need to maintain the position of elements in List1
Here is sample of what I'm doing
Here is sample of what I'm doing
As LP13's answer points out, you're doing a large amount of re-computation by re-executing a query instead of executing it once and caching the result.
But the larger problem here is that if you have n items in List1 and m potential matches in List2, and you are looking for any match, then worst case you will definitely do n * m matches. If n and m are large, their product is rather larger. And since we're looking for any match, the worst case is when there is no match; you'll definitely try all m possibilities.
Is this cost avoidable? Maybe, but only if we know some trick to take advantage of, and you've made the problem so abstract -- we have two lists and a relation, and no information about either the lists or the relation -- that there is no structure that we can take advantage of.
That said: if you happen to know that there is an element in List2 that is likely to match many items in List1 then put that element first. Any, or FirstOrDefault, will stop executing the Where query after getting the first match, so you can turn an O(n * m) problem into an O(n) problem.
Without knowing more about what the relation is, it's hard to say how to improve the performance.
UPDATE: A commenter points out that we can do better if we know that the relation is an equivalence relation. Is it an equivalence relation? That is, suppose we have your method that checks two items. Are we guaranteed the following?
The relation is reflexive: CheckMatch(a, a) is always true.
The relation is symmetric: CheckMatch(a, b) is always the same as CheckMatch(b, a)
The relation is transitive: if CheckMatch(a, b) is true and CheckMatch(b, c) is true then CheckMatch(a, c) is always true
If we have those three conditions then you can do considerably better. Such a relation partitions elements into equivalence classes. What you do is associate each item in List1 and List2 with a canonical value. That canonical value is the same for every member of the equivalence class. From that dictionary you can then do fast lookups and solve your problem quickly.
But if your relation is not an equivalence relation, this does not work.
Can you try this? When you do only .Where it produces IEnumerable and then you are doing First() and Any() on IEnumerable
foreach(var item1 in List1)
{
var matchingItem = List2.Where(item2 => CheckMatch(item1, item2)).FirstOrDefault();
if (matchingItem != null)
{
item1.IsExclude = matchingItem.IsExcluded;
item1.IsInclude = matchingItem.IsIncluded;
item1.Category = matchingItem.Category;
}
}

C# Structure that sorts key pairs and is accessible?

Noob here. I've been scouring the internet for days, and cannot find a decent structure that auto-sorts data (like SortedSet), while still allowing that data to be accessible (like List). Here's what I have:
A list containing 100,000 nodes, added and modified regularly.
List<Nodes> nodes;
The node object, containing data I need to access/change
public class Node (string name, int index){ doSomething(); }
I don't wish to be vague, but can't sort the actual list because the index is a history of when nodes were added. Thus, I want to use a structure that auto-sorts KeyValuePair pairs(where string is the name to be sorted by, and int is the index as it is found in my list of nodes), but I must be able to access the value. Here's what I want to do:
// Add a node to the list, then to the structure
int index = nodes.Count;
nodes.Add(new Node("someName", index));
someStructure.Add("someName", index);
// Give name to structure, which returns int value for use in finding node
node[someStructure.findValueOf("someName"))].doSomething();
This would tell the node with the name "someName" to doSomething();
I am positive that I am missing something. I've tried using SortedSet, SortedList, Dictionary, etc. In each case, I can't retrieve the sorted object. What is the purpose of auto-sorting if I can't find out where they are at? Please help my poor life.
You are looking for a SortedDictionary.
As per the documentation: Represents a collection of key/value pairs that are sorted on the key. Although, as some comments say, those 100k objects would be better kept in a database...
Link: https://msdn.microsoft.com/en-us/library/f7fta44c(v=vs.110).aspx
You can use SortedList and LINQ:
SortedList<int,string> list = new SortedList<int, string>();
list.Add(1, "name1");
list.Add(2, "name2");;
var c = list.Select(x => x.Value == "name2").FirstOrDefault();
However I agree with a Christopher's comment about using db.

How to get values into list from nested concurrent dictionary in c#

I have a nested concurrent dictionary as given below:
ConcurrentDictionary<string,ConcurrentDictionary<string,<Class Object>>>
I want to get all objects (values of inner dictionary) into list for further processing without knowing any key.
I tried below two solutions but it does not work for me,
outer dictionary.Values.Select(x=> x.Values)
foreach loop
The problem with first solution is that it won't give only objects and second solution is time consuming.
If you run dictionary.Values.Select(x=> x.Values) you would not get a list of object values from the inner dictionaries; you will get a list of lists of object values.
To "flatten" that list, use SelectMany:
foreach (var inner in dictionary.Values.SelectMany(x=> x.Values)) {
...
}

C# List<string> contains partial match from another List<string>

I have these lists:
var list1 = new List<string>
{
"BOM_Add",
"BOM_Edit",
"BOM_Delete",
"Paper_Add",
"Paper_Edit",
"Paper_Delete"
};
var list2 = new List<string> {"BOM", "Paper_Add"};
I want to create a third list of the common items based on a partial match. So, the third list should contain:
"BOM_Add",
"BOM_Edit",
"BOM_Delete",
"Paper_Add"
because the second list contains "BOM".
If the second list contained "_Edit", then I would expect the third list to have
"BOM_Edit",
"Paper_Edit"
I know how to do this with .Intersect() if I spell out each item (e.g. "BOM_Add") in the second list, but I need it to be more flexible than that.
Can this be done without iterating through each item on the first list? These lists may get very long and I would prefer to avoid that if I can.
You can use LINQ
var result = list1.Where(r => list2.Any(t => r.Contains(t)))
.ToList();
For output:
foreach (var item in result)
{
Console.WriteLine(item);
}
Output would be:
BOM_Add
BOM_Edit
BOM_Delete
Paper_Add
Can this be done without iterating through each item on the first
list?
You have to iterate, either through a loop or using LINQ (which internally iterates as well)
Can this be done without iterating through each item on the first list?
No, if you want to find all of the items that contain one of the items that you have. There is no way of building an index, or any sort of structure that can rule out large sections of items without checking each one. The only option is to compare every single item in the first list with every single item in the other list, doing your Contains check.
If you only needed to do a StartsWith instead of a Contains, then you could sort your list, do a BinarySearch to find the item nearest to the item that you're searching for, which would allow you to easily find all of the items that start with a particular string while only actually needing to check O(log(n) + m) items (where n is the size of the list an m is the average number of matches). You could do the same thing with an EndsWith too, if you just sorted items based on the reverse of the string, but there's no way to sort an items such that a Contains check does this.

Which data structure should I use for having sorted data, where the key can be used on multiple entries

I have some set of data to store where I have a key to find the object related, but the key is not unique and the same key can have multiple pointers.
I would like to be able to throw this data into a structure a bit like the SortedList, but it require unique keys to work.
Is there any out of the box C# object that will allow me to do this. In following example I am using a string as reference object, but it might as well be any other object, just like a SortedList can contain any type of object.
eg.
unknownDatastructure structure = new unknownDatastructure<string, string>();
structure.add("left","the remainder after a removal");
structure.add("left","a direction opposite of right");
structure.add("right","a direction opposite of left");
structure.add("right","opposite of being wrong");
and I would like to either get an array of objects back that matches the search key when called, or first entry (and I can find remaining via the index).
eg.
List<string> results = structure.FindAll("Left");
Where the List would contain the actual referenced object, in this case "the remainder of a removal" and "a direction opposite of right".
int firstmatch = structure.FindIndex("Right");
Where the int would be 2 (0 = first left, 1 = second left, 2 = first right, 3 = second right). I do not care which order the 2 lefts or the 2 rights are sorted, just need to be able to locate the entry of the first repeat, then I can step forward through all entries as required to create the "FindAll" function
Dictionary<K,V> does not support duplicate keys. You will have to maintain a list of all entries for each key:
Dictionary<string, List<string>>
Just create your own:
Dictionary<TKey, List<TValue>> dictionary;
Then your code would look a little like:
List<TValue> list;
if(!dictionary.TryGetValue(key, out list))
{
list = new List<TValue>();
dictionary[key] = list;
}
list.Add("whatever...");
You could look into Tuple or Anonymous Types.
Is there any reason you don't want to create a class or struct to contain your data? It would allow you to easily add functionality later on.
Adding either of the above to a List<T> will let you find the element by using a predicate. myList.FindAll(x => x.MyKey == "left");

Categories