Reputation: 433
I have three lists of objects each of which are linked to one other list by a single common property, Parent
and Node
in the following hierarchy: Model -> Intermediate -> Results. I have the following code:
class Result
{
public string Name { get; set; }
public int Node{ get; set; }
public int Parent{ get; set; }
}
class Intermediate
{
public int Node{ get; set; }
public int Parent{ get; set; }
}
class Model
{
public string Name { get; set; }
public int Node{ get; set; }
public int Parent{ get; set; }
}
public class Example
{
public static void Main()
{
List<Result> results = new List<Result>();
List<Intermediate> intermediates = new List<Intermediate>();
List<Model> models = new List<Model>();
// Example objects in the list
results.Add(new Result() { Name = "", Parent = 21, Node = 101 });
intermediates.Add(new Part() { Parent = 11, Node = 21 });
models.Add(new Part() { Name = "ABCD", Parent = 1, Node = 11 });
...
}
}
As can be seen the Model
object links to Intermediate
object via model.Node
and intermediate.Parent
, and the Intermediate
object links to Results
object via intermediate.Node
and results.Parent
.
Note the lists can contain thousands of items, each added using a similar format as above.
What I want to be able to do is add the names from the Model
objects in list to the matching Results
objects in the results
list.
My thinking is that I can loop through each object in the Intermediate
list and find (using LINQ) the Result
object where intermediate.Node = result.Parent
, and then either replace the value of the result.Parent
with intermediate.Parent
, or add a new Grandparent
property to the Result
object in which to put the intermediate.Parent
. Then repeat the process looping through each of the objects in the models
list finding the matching Result
object and adding the Name
.
So I guess my question is, is this the best way of doing this, or is there a more efficient way? I have many lists where the same will have to be repeated, so was wondering if there was a better way as it can be quite slow looping through every object. Also is there a way to get from the first list directly to the third list.
I hope this is well enough explained. I am quite a beginner when it comes to C#.
Upvotes: 0
Views: 2576
Reputation: 2685
Smells like Composite Pattern what you talk about here.
And you can use HashSet to keep your values to perform it fast.
public class Item
{
public Item(int itemNode)
{
Node = itemNode;
Children = new HashSet<Item>();
}
public int Node { get; set; }
public Item Parent { get; set; }
private HashSet<Item> Children { get; set; }
public bool Add(Item item)
{
item.Parent = this;
return Children.Add(item);
}
public List<Item> Find(Func<Item, bool> predicate)
{
var found = new List<Item>();
if (predicate(this)) found.Add(this);
Collect(predicate, found);
return found;
}
public void Collect(Func<Item, bool> predicate, List<Item> collected = null)
{
collected = collected ?? new List<Item>();
collected.AddRange(Children.Where(predicate).ToList());
foreach (var child in Children)
{
child.Collect(predicate, collected);
}
}
}
public class Model : Item //this is your model
{
public string Name { get; set; }
public Model(int itemNode, string name) : base(itemNode)
{
Name = name;
}
public List<Item> GetNamesMatchingWith(Func<Item, bool> predicate)
{
return Find(predicate);
}
}
public class Example
{
public static void Main()
{
var root = new Model(0, "root");
var one = new Model(1, "1");
var two = new Model(2, "2");
var tree = new Model(3, "3");
root.Add(one);
root.Add(two);
root.Add(tree);
var a = new Model(4, "a");
var b = new Model(5, "b");
two.Add(a);
two.Add(b);
var namesMatchingWith = root.GetNamesMatchingWith(x=> x.Parent!=null && x.Parent.Node == 2);
Console.ReadKey();
}
}
Hope it inpires you..
Upvotes: 0
Reputation: 21487
You actually have Results -> Intermediate -> Model instead of Model -> Intermediate -> Results.
To speed the process of removing the Intermediate, build a dictionary. Then you can do a simple select on Results using the dictionary to convert.
var intermediateDict=intermediates.ToDictionary(key=>key.Node,val=>val.Parent);
var newresults=results.Select(r=>new Result {
Name=r.Name,
Node=r.Node,
Parent=intermediateDict[r.Parent]
});
You can also do joins to get the final answer.
Upvotes: 3
Reputation: 9490
It looks a foreach loop can be used to get to the result (leaf) nodes and assign the model name to result nodes:
var theModel = models.First(); // select a model
foreach (var interm in intermediates.Where(x => x.Parent == theModel.Node))
{
foreach (var res in results.Where(x => x.Parent == interm.Node))
{
res.Name = theModel.Name;
}
}
Upvotes: 1