I've got a Type that we'll call Foo that can hold a collection of children Foo objects. Foo is Disposable, so when ever a child is disposed of, it will then add itself to the parent's Children collection.
An example usage of this looks like:
using (var a = AddChild(Root, "a"))
{
using (var a1 = AddChild(a, "a1"))
{
using (var a1a = AddChild(a1, "a1a"))
{
}
}
In this example a1a is only added to a1 when it is disposed, and not before. What I am having difficulty in figuring out is a clean way of writing a GetAllFoos method that returns all of the objects in a flattened list, in a FILO order.
In this case, would I just recursively iterate over each child, or is there some fancy LINQ I can use to try and consolidate these collections? I'm using this to take performance measurement snapshots through-out the app, and it's possible that we would call GetAllMeasurements in some cases during a profile so the performance of the method call is important.
This is a complete example app that shows what the expected results would look like. I have to support both FIFO and FILO. I've got a FIFO implementation working but I'm not sure on the best way to handle this inversely for FILO.
using System;
using System.Collections.Generic;
using System.Linq;
namespace FILO_Example
{
public class Foo : IDisposable
{
internal Foo parent;
public Foo(Foo parent = null)
{
this.parent = parent;
}
public string Name { get; set; }
public List<Foo> Children { get; } = new List<Foo>();
public void Dispose() => this.parent.Children.Add(this);
}
class Program
{
public static Foo Root { get; } = new Foo { Name = "Root" };
static void Main(string[] args)
{
// level 1
using (var a = AddChild(Root, "a"))
{
using (var a1 = AddChild(a, "a1"))
{
using (var a1a = AddChild(a1, "a1a"))
{
}
}
using (var a2 = AddChild(a, "a2"))
{
}
}
using (var b = AddChild(Root, "b"))
{
using (var b1 = AddChild(b, "b1"))
{
}
}
List<Foo> allFoos = GetAllFoosFILO().ToList();
Console.WriteLine(allFoos[0]); // Should be b1
Console.WriteLine(allFoos[1]); // Should be b
Console.WriteLine(allFoos[2]); // Should be a2
Console.WriteLine(allFoos[3]); // Should be a1a
Console.WriteLine(allFoos[4]); // Should be a1
Console.WriteLine(allFoos[5]); // Should be a
}
static IEnumerable<Foo> GetAllFoosFILO()
{
return new List<Foo>();
}
static IEnumerable<Foo> GetAllFoosFIFO()
{
var fooStack = new Stack<Foo>();
fooStack.Push(Root);
while (fooStack.Count > 0)
{
Foo currentFoo = fooStack.Pop();
yield return currentFoo;
// If we have children, add them in reverse order so that it's a First-In-First-Out stack
// then the while loop will yield each child element.
if (currentFoo.Children.Count > 0)
{
List<Foo> fooChildren = currentFoo.Children;
for (int currentIndex = fooChildren.Count - 1; currentIndex >= 0; currentIndex--)
{
fooStack.Push(fooChildren[currentIndex]);
}
}
}
}
static Foo AddChild(Foo parent, string name)
{
var child = new Foo(parent) { Name = name };
return child;
}
}
}
As I mentioned in the comments, you have a tree structure. There is no fancy efficient standard LINQ solution, but you can utilize the quite efficient generic Traverse method form my answer to Enumerating Directories iteratively in "postorder":
public static class TreeHelper
{
public static IEnumerable<T> Traverse<T>(T node, Func<T, IEnumerable<T>> childrenSelector, bool preOrder = true)
{
var stack = new Stack<IEnumerator<T>>();
var e = Enumerable.Repeat(node, 1).GetEnumerator();
try
{
while (true)
{
while (e.MoveNext())
{
var item = e.Current;
var children = childrenSelector(item);
if (children == null)
yield return item;
else
{
if (preOrder) yield return item;
stack.Push(e);
e = children.GetEnumerator();
}
}
if (stack.Count == 0) break;
e.Dispose();
e = stack.Pop();
if (!preOrder) yield return e.Current;
}
}
finally
{
e.Dispose();
while (stack.Count != 0) stack.Pop().Dispose();
}
}
}
With that helper, the GetAllFoosFIFO() is simple as that:
static IEnumerable<Foo> GetAllFoosFIFO()
{
return TreeHelper.Traverse(Root, foo => foo.Children.Count > 0 ? foo.Children : null);
}
while for GetAllFoosFILO() you need to pass preorder = false and iterate Children in reverse order:
static IEnumerable<Foo> GetAllFoosFILO()
{
return TreeHelper.Traverse(Root, foo => foo.Children.Count > 0 ?
Enumerable.Range(0, foo.Children.Count)
.Select(i => foo.Children[foo.Children.Count - 1 - i]) : null, false);
}
This should work:
private static IEnumerable<Foo> GetAllFoosFILO(Foo foo)
{
foreach (var c in ((IEnumerable<Foo>)foo.Children).Reverse())
{
var cc = GetAllFoosFILO(c);
foreach (var ccc in cc)
{
yield return ccc;
}
yield return c;
}
}
The weird cast in first foreach loop is for preventing use of List<T>.Reverse instead of Enumerable.Reverse<TSource> extension method which helps us to traverse tree in so called FILO way.
Bonus
With some small touches you can write FIFO like:
private static IEnumerable<Foo> GetAllFoosFIFO(Foo foo)
{
foreach (var c in foo.Children)
{
yield return c;
var cc = GetAllFoosFIFO(c);
foreach (var ccc in cc)
{
yield return ccc;
}
}
}
So I have been struggling to find a way to create all combinations with no repetition from multiple lists containing custom objects. There are some additional constraints that make it a bit more challenging, of course.
Basically I am parsing a bunch of data from a .csv file that contains part information. This data is then passed on to a custom object and then those objects are added to lists based on their "group." (See code below)
So once the information has been parsed I now have 6 lists containing any number of elements. Now I need to generate all combinations between those 6 lists following these rules:
One object from groupA
Two objects from groupB (no repetition)
Three objects from groupC (no repetition)
One object from groupD
One object from groupE
One object from groupF
These objects are then used to create a ModuleFull object, and my overall end result should be a List<ModuleFull> containing all the combinations generated from the part lists.
I was able to figure out a way to do this using LINQ although I did not test it using lists of custom objects because I realized my lists all contain different numbers of elements.
So any help that I could get in coming up with a method to solve this using recursion would be greatly appreciated.
Here is the code parsing the data:
using (TextFieldParser parser = new TextFieldParser(#"c:\temp\test.csv"))
{
parser.TextFieldType = FieldType.Delimited;
parser.SetDelimiters(",");
while (!parser.EndOfData)
{
string[] fields = parser.ReadFields();
Part tempPart = new Part(fields[0], fields[2], fields[1], double.parse(fields[4]), long.parse(fields[3]));
allParts.Add(tempPart);
if (tempPart.group == "A")
{
aParts.Add(tempPart);
}
else if (tempPart.group == "B")
{
bParts.Add(tempPart);
}
else if (tempPart.group == "C")
{
cParts.Add(tempPart);
}
else if (tempPart.group == "D")
{
dParts.Add(tempPart);
}
else if (tempPart.group == "E")
{
eParts.Add(tempPart);
}
else if (tempPart.group == "F")
{
fParts.Add(tempPart);
}
}
Below are the two classes for the objects that fill the lists:
public class Part
{
public string idNum; //0 locations when being parsed
public string name; //2
public string group; //1
public double tolerance; //4
public long cost; //3
public Part(string id, string nm, string grp, double tol, long cst)
{
idNum = id;
name = nm;
group = grp;
tolerance = tol;
cost = cst;
}
}
public class ModuleFull
{
public Part groupA;
public Part groupBOne;
public Part groupBTwo;
public Part groupCOne;
public Part groupCTwo;
public Part groupCThree;
public Part groupD;
public Part groupE;
public Part groupF;
public ModuleFull(Part a, Part b1, Part b2, Part c1, Part c2, Part c3, Part d, Part e, Part f)
{
groupA = a;
groupBOne = b1;
groupBTwo = b2;
groupCOne = c1;
groupCTwo = c2;
groupCThree = c3;
groupD = d;
groupE = e;
groupF = f;
}
}
The code below uses a custom enumerator to get unique combinations. Very clean solution.
using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.IO;
namespace IEnumerable_IEnumerator_Recursive
{
class Program
{
const string FILENAME = #"c:\temp\test.csv";
static void Main(string[] args)
{
Parser parser = new Parser(FILENAME);
int level = 0;
List<Part> root = new List<Part>();
Part.Recurse(level, root);
}
}
public class Parser
{
public Boolean EndOfData = false;
public Parser(string filename)
{
StreamReader reader = new StreamReader(filename);
string inputLine = "";
while ((inputLine = reader.ReadLine()) != null)
{
inputLine = inputLine.Trim();
if (inputLine.Length > 0)
{
string[] fields = inputLine.Split(new char[] { ',' });
Part tempPart = new Part(fields[0], fields[1], fields[2], fields[3], fields[4]);
Part.allParts.Add(tempPart);
}
}
Part.MakeDictionary();
}
}
public class PartEnumerator : IEnumerator<List<Part>>
{
List<Part> parts = null;
public static SortedDictionary<string, int> maxCount = new SortedDictionary<string, int>() {
{"A", 1},
{"B", 2},
{"C", 3},
{"D", 1},
{"E", 1},
{"F", 1}
};
public int size = 0;
List<int> enumerators = null;
public PartEnumerator(string name, List<Part> parts)
{
this.parts = parts;
size = maxCount[name];
enumerators = new List<int>(new int[size]);
Reset();
}
object IEnumerator.Current
{
get
{
return Current;
}
}
public List<Part> Current
{
get
{
try
{
List<Part> returnParts = new List<Part>();
foreach (int enumerator in enumerators)
{
returnParts.Add(parts[enumerator]);
}
return returnParts;
}
catch (IndexOutOfRangeException)
{
throw new InvalidOperationException();
}
}
}
public void Reset()
{
for (int count = 0; count < enumerators.Count; count++)
{
enumerators[count] = count;
}
}
public Boolean MoveNext()
{
Boolean moved = true;
int listSize = parts.Count;
int enumNumbers = enumerators.Count;
//only use enumerators up to the size of list
if (listSize < enumNumbers)
{
enumNumbers = listSize;
}
Boolean ripple = true;
int enumCounter = enumNumbers;
if (enumCounter > 0)
{
while ((ripple == true) && (--enumCounter >= 0))
{
ripple = false;
int maxCount = listSize - (enumNumbers - enumCounter);
if (enumerators[enumCounter] >= maxCount)
{
ripple = true;
}
else
{
for (int i = enumCounter; i < enumNumbers; i++)
{
if (i == enumCounter)
{
enumerators[i] += 1;
}
else
{
enumerators[i] = enumerators[i - 1] + 1;
}
}
}
}
if ((enumCounter <= 0) && (ripple == true))
{
moved = false;
}
}
return moved;
}
public void Dispose()
{
}
}
public class Part
{
public static List<Part> allParts = new List<Part>();
public static Dictionary<string, PartEnumerator> partDict = new Dictionary<string, PartEnumerator>();
public string idNum; //0 locations when being parsed
public string name; //2
public string group; //1
public double tolerance; //4
public long cost; //3
public Part()
{
}
public Part(string id, string nm, string grp, string tol, string cst)
{
idNum = id;
name = nm;
group = grp;
tolerance = double.Parse(tol);
cost = long.Parse(cst);
}
public static void MakeDictionary()
{
var listPartEnum = Part.allParts.GroupBy(x => x.name)
.Select(x => new { Key = x.Key, List = new PartEnumerator(x.Key, x.ToList()) });
foreach (var partEnum in listPartEnum)
{
partDict.Add(partEnum.Key, partEnum.List);
}
}
public static string[] NAMES = { "A", "B", "C", "D", "E", "F" };
public static void Recurse(int level, List<Part> results)
{
Boolean moved = true;
if (level < PartEnumerator.maxCount.Keys.Count)
{
//level is equivalent to names in the Part Enumerator dictionary A to F
string name = NAMES[level];
PartEnumerator enumerator = partDict[name];
enumerator.Reset();
while ((enumerator != null) && moved)
{
List<Part> allParts = new List<Part>(results);
allParts.AddRange((List<Part>)enumerator.Current);
int currentLevel = level + 1;
Recurse(currentLevel, allParts);
moved = enumerator.MoveNext();
}
}
else
{
string message = string.Join(",", results.Select(x => string.Format("[id:{0},name:{1}]", x.name, x.idNum)).ToArray());
Console.WriteLine(message);
}
}
}
}
I used following input file
1,A,X,0,0
2,A,X,0,0
3,A,X,0,0
4,A,X,0,0
5,A,X,0,0
1,B,X,0,0
2,B,X,0,0
3,B,X,0,0
4,B,X,0,0
5,B,X,0,0
1,C,X,0,0
2,C,X,0,0
3,C,X,0,0
4,C,X,0,0
5,C,X,0,0
1,D,X,0,0
2,D,X,0,0
3,D,X,0,0
4,D,X,0,0
5,D,X,0,0
1,E,X,0,0
2,E,X,0,0
3,E,X,0,0
4,E,X,0,0
5,E,X,0,0
1,F,X,0,0
2,F,X,0,0
3,F,X,0,0
4,F,X,0,0
5,F,X,0,0
This can be solved with two related methods. One is a method to generate all combinations of items from a list. This deals with your cases where you want more than one from a set, like group B and C. The other is a method to get you all the ways to combine one element from each list, which is otherwise known as a Cartesian product and is, in a way, a special case of the first method.
I recently wrote a library of combinatorial functions that includes both of these, so I can share my implementation with you. My library is on Github if you want to look at the source code, and can be installed from NuGet if you'd like. (The examples below are slightly simplified to fit your situation; in my fuller versions, the combinations method has different modes that allow you to specify whether it matters what order the output items are in, and whether it's allowed to use source items more than once. Neither are needed here, so they've been omitted.)
So, the first of those methods looks something like this:
public static IEnumerable<IEnumerable<T>> Combinations<T>(this IEnumerable<T> source, int combinationSize)
{
if (combinationSize > source.Count())
{
return new List<IEnumerable<T>>();
}
if (source.Count() == 1)
{
return new[] { source };
}
var indexedSource = source
.Select((x, i) => new
{
Item = x,
Index = i
})
.ToList();
return indexedSource
.SelectMany(x => indexedSource
.OrderBy(y => x.Index != y.Index)
.Skip(1)
.OrderBy(y => y.Index)
.Skip(x.Index)
.Combinations(combinationSize - 1)
.Select(y => new[] { x }.Concat(y).Select(z => z.Item))
);
}
The second method is from a blog post by Eric Lippert (which was actually inspired by another StackOverflow question), and looks like this:
public static IEnumerable<IEnumerable<T>> CartesianProduct<T>(this IEnumerable<IEnumerable<T>> sequences)
{
if (sequences == null)
{
throw new ArgumentNullException(nameof(sequences));
}
IEnumerable<IEnumerable<T>> emptyProduct = new IEnumerable<T>[] { Enumerable.Empty<T>() };
return sequences.Aggregate(
emptyProduct,
(accumulator, sequence) =>
from accseq in accumulator
from item in sequence
select accseq.Concat(new[] { item }))
.Where(x => x.Any());
}
The two methods can be combined like this:
var groupA = new[] { "a", "aa", "aaa", "aaaa", "aaaaa" };
var groupB = new[] { "b", "bb", "bbb", "bbbb", "bbbbb" };
var groupC = new[] { "c", "cc", "ccc", "cccc", "ccccc" };
var groupD = new[] { "d", "dd", "ddd", "dddd", "ddddd" };
var groupE = new[] { "e", "ee", "eee", "eeee", "eeeee" };
var groupF = new[] { "f", "ff", "fff", "ffff", "fffff" };
var options = new[]
{
groupA.Combinations(1), // One object from groupA
groupB.Combinations(2), // Two objects from groupB (no repetition)
groupC.Combinations(3), // Three objects from groupC (no repetition)
groupD.Combinations(1), // One object from groupD
groupE.Combinations(1), // One object from groupE
groupF.Combinations(1) // One object from groupF
};
return options.CartesianProduct();
So, we generate the various ways of satisfying each of your sub-conditions first: one from this group, two from that group, etc. Then, we look at all ways of putting those together to form a group of subgroups. The result is an IEnumerable<IEnumerable<T>> where T is the type of what you started with - in this case, string, but for you it could be something else. You can then iterate over this and use each set to build your result type.
Be aware that, like many combinatorial problems, this can scale quite fast. For example, with my test data this returns 62,500 possible combinations.
I'm looking for a more lazy/IEnumerable/cleaner way of doing the following. I particularly not happy with the use of helper and Aggregate.
Any hints on how to modify the code to make it possible?
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Test1
{
class Program
{
static void PrintOut<T>(IEnumerable<IEnumerable<T>> data)
{
foreach (var item in data)
{
string output = "-";
if (item != null)
output = string.Join(",", item.Select(x => (x == null) ? "-" : x.ToString()));
Console.WriteLine(output);
}
}
static IEnumerable<T> helper<T>(IEnumerable<T> orig, T toAdd)
{
if (orig != null)
foreach (var item in orig)
yield return item;
yield return toAdd;
yield break;
}
static IEnumerable<IEnumerable<T>> helper2<T>(IEnumerable<IEnumerable<T>> input) where T : class
{
var initalAcc = new List<IEnumerable<T>> { };
var result = input.Aggregate(initalAcc,
(acc, choiceSet) =>
acc.DefaultIfEmpty()
.SelectMany((chosen) => (choiceSet ?? new List<T> { }).DefaultIfEmpty().Select(choice => helper(chosen, choice))).ToList()
);
return result;
}
static void Main(string[] args)
{
var preCombination = new List<List<string>> {
new List<string> {"1","2"},
new List<string> {"3"},
new List<string> {"4","5"},
null,
new List<string> {"6","7"}
};
var postCombination = helper2(preCombination);
PrintOut(preCombination);
Console.WriteLine();
PrintOut(postCombination);
Console.ReadLine();
}
}
}
Here is the expected output
1,2
3
4,5
-
6,7
1,3,4,-,6
1,3,4,-,7
1,3,5,-,6
1,3,5,-,7
2,3,4,-,6
2,3,4,-,7
2,3,5,-,6
2,3,5,-,7
I've changed initalAcc now
var initalAcc = Enumerable.Empty<IEnumerable<T>>();
Here you go. ConcatItem and Yield replace helper.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Test1
{
class Program
{
static void PrintOut<T>(IEnumerable<IEnumerable<T>> data)
{
foreach (var item in data)
{
string output = "-";
if (item != null)
output = string.Join(",", item.Select(x => (x == null) ? "-" : x.ToString()));
Console.WriteLine(output);
}
}
static IEnumerable<T> Yield<T>(T item)
{
yield return item;
}
static IEnumerable<T> ConcatItem<T>(IEnumerable<T> enumerable, T item)
{
return enumerable == null ? Yield(item) : enumerable.Concat(Yield(item));
}
static IEnumerable<IEnumerable<T>> helper2<T>(IEnumerable<IEnumerable<T>> input) where T : class
{
var initalAcc = Enumerable.Empty<IEnumerable<T>>();
var result = input.Aggregate(initalAcc,
(acc, choiceSet) =>
acc.DefaultIfEmpty()
.SelectMany((chosen) => (choiceSet ?? Enumerable.Empty<T>()).DefaultIfEmpty().Select(choice => ConcatItem(chosen, choice)))
);
return result;
}
static void Main(string[] args)
{
var preCombination = new List<List<string>> {
new List<string> {"1","2"},
new List<string> {"3"},
new List<string> {"4","5"},
null,
new List<string> {"6","7"},
};
var postCombination = helper2(preCombination);
PrintOut(preCombination);
Console.WriteLine();
PrintOut(postCombination);
Console.ReadLine();
}
}
}
I have a sorted list that will pass in two elements and compare the two. Is there a function in the SortedList class in C# that will do a next and previous? I got some help with a .Skip, but since the keys would be variable, how would that work? All I need to do is take in the first element and second element, then skip to the third and fourth, fifth and sixth, etc. I wish it were as simple as LinkedList's ".next.next."
double velocity = positionList.Values.Skip(1);
Edit: The positionList is type
<double, HandCoordinate>
HandCoordinate = {double, double, double}
Does that help?
Thanks!
The class SortedList inherites IEnumerator, so you can use it:
SortedList list = ...
var listEnumerator = ((IEnumerable)list).GetEnumerator();
Pair<MyType> pair = null
do
{
pair = Pair.Next<MyType>(listEnumerator);
...
}
while(pair != null)
...
class Pair<T>
{
public T First {get; set;}
public T Second {get; set;}
public static Pair<T> Next<T>(IEnumerator enumerator)
{
var first = enumerator.Current;
if(enumerator.MoveNext())
{
return new Pair<T>
{
First = (T)first,
Second = (T)enumerator.Current,
}
}
return null;
}
}
List<int> ints = new List<int>();
ints.Add(1);
ints.Add(2);
ints.Add(3);
ints.Add(4);
for (int i = 0; i < ints.Count; i += 2)
{
var pair = ints.Skip(i).Take(2);
var first = pair.First();
var last = pair.Last();
}
Note: This should work, irrelevant of the type in theory. Unless the type is a drastically different format.
Without Skip().
var pair = new { First = ints[i], Second = ints[i += 1] };
The question is somewhat unclear. I'm assuming you need to get pairs of things from a list?
It's fairly easy to write an extension method that will present a sequence of pairs of items from an IEnumerable:
using System;
using System.Collections.Generic;
namespace Demo
{
internal static class Program
{
public static void Main()
{
double[] test = new double[] {1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
foreach (var pair in test.AsPairs()) // This is how you use it.
{
Console.WriteLine("({0}, {1})", pair.Item1, pair.Item2);
// Or simply: Console.WriteLine(pair);
}
}
}
public static class EnumerableExt
{
public static IEnumerable<Tuple<T, T>> AsPairs<T>(this IEnumerable<T> sequence)
{
bool isFirst = true;
T first = default(T);
foreach (var item in sequence)
{
if (isFirst)
{
first = item;
isFirst = false;
}
else
{
isFirst = true;
yield return new Tuple<T, T>(first, item);
}
}
}
}
}
It's my understanding that if I want to get the ID of an item in a list, I can do this:
private static void a()
{
List<string> list = new List<string> {"Box", "Gate", "Car"};
Predicate<string> predicate = new Predicate<string>(getBoxId);
int boxId = list.FindIndex(predicate);
}
private static bool getBoxId(string item)
{
return (item == "box");
}
But what if I want to make the comparison dynamic? So instead of checking if item=="box", I want to pass in a user-entered string to the delegate, and check if item==searchString.
Using a compiler-generated closure via an anonymous method or lambda is a good way to use a custom value in a predicate expression.
private static void findMyString(string str)
{
List<string> list = new List<string> {"Box", "Gate", "Car"};
int boxId = list.FindIndex(s => s == str);
}
If you're using .NET 2.0 (no lambda), this will work as well:
private static void findMyString(string str)
{
List<string> list = new List<string> {"Box", "Gate", "Car"};
int boxId = list.FindIndex(delegate (string s) { return s == str; });
}
You can just do
string item = "Car";
...
int itemId = list.FindIndex(a=>a == item);
string toLookFor = passedInString;
int boxId = list.FindIndex(new Predicate((s) => (s == toLookFor)));
List <string> list= new List<string>("Box", "Gate", "Car");
string SearchStr ="Box";
int BoxId= 0;
foreach (string SearchString in list)
{
if (str == SearchString)
{
BoxId= list.IndexOf(str);
break;
}
}