How to move from an iterative approach to a recursive approach

I have an iterative C # loop that fills a table template with up to 5 columns.

The values โ€‹โ€‹are paired, it is always the heading and several values โ€‹โ€‹for each column, and it combines the values โ€‹โ€‹with a non-repeating combination.

Starting with the simplest solution that I could imagine, and looking at it, I thought that there should be a better approach for this problem, doing it recursively.

Below is an example of what I have tried so far:

List<EtOfferVariant> variants = new List<EtOfferVariant>(); _containers[0].Variant.ForEach(first => { if (_containers.Count > 1) { _containers[1].Variant.ForEach(second => { if (_containers.Count > 2) { _containers[2].Variant.ForEach(third => { EtOfferVariant va = new EtOfferVariant(); va.OfferVariant1Type = _containers[0].VariantKey; va.OfferVariant1 = first; va.OfferVariant2Type = _containers[1].VariantKey; va.OfferVariant2 = second; va.OfferVariant3Type = third; va.OfferVariant3 = _containers[3].VariantKey; variants.Add(va); }); } else { EtOfferVariant va = new EtOfferVariant(); va.OfferVariant1Type = _containers[0].VariantKey; va.OfferVariant1 = first; va.OfferVariant2Type = second; va.OfferVariant2 = _containers[1].VariantKey; variants.Add(va); } }); } else { EtOfferVariant va = new EtOfferVariant(); va.OfferVariant1Type = _containers[0].VariantKey; va.OfferVariant1 = first; variants.Add(va); } }); 

Containers consist of a list of strings (values) and a key (header).

This is an example version of OfferVariant in a real example totals up to 5.

I cannot change the structure of the inital checkboard because it is defined by an existing database.

The following is an illustration of data input and output for 2 containers consisting of:

Container 1:

  • Key: pie
  • Values:
    • Raspberries
    • Strawberry

Container 2:

  • Key: Drink
  • Values:
    • Cola
    • Coffee

The generated output will consist of 4 lines containing

due to the fact that it is easily skipped, as shown here.

The result will be a row in the database consisting of 4 columns

 Column 1 | Column 2 | Column 3 | Column 4 Pie | Raspberry | Drink | Cola Pie | Raspberry | Drink | Coffee Pie | Strawberry| Drink | Cola Pie | Strawberry| Drink | Coffee 

EtOfferVariant is the ORM Poco containing these columns

+6
source share
3 answers

Thank you for your answers, Martin Livergard, as if to direct me to mind, the hard was not a pure Cartesian product because the fact was grouped to be released last and the Cines approach gave me the end point in the right direction, I decided this in the following way

in the first stage I generate inital lines for the first option

  List<EtOfferVariant> row = new List<EtOfferVariant>(); _containers.First().Variant.ForEach(o => { row.Add(new EtOfferVariant() { OfferVariant1 = o, OfferVariant1Type = _containers.First().VariantKey }); }); return BuildVariants(row); 

and then run it through

  private List<EtOfferVariant> BuildVariants(List<EtOfferVariant> row, int containerIndex = 1) { List<EtOfferVariant> final = new List<EtOfferVariant>(); row.ForEach(y => { for (int i = 0; i < _containers[containerIndex].Variant.Count; i++) { var ret = MultiplyFromPrevious(y); FillByIndex(ret, _containers[containerIndex].Index, _containers[containerIndex].VariantKey, _containers[containerIndex].Variant[i]); final.Add(ret); } }); containerIndex++; if (containerIndex < _containers.Count) return BuildVariants(final, containerIndex); return final; } 

and thanks again cine

 private EtOfferVariant MultiplyFromPrevious(EtOfferVariant variant) { EtOfferVariant ret = new EtOfferVariant(); ret.OfferVariant1 = variant.OfferVariant1; ret.OfferVariant2 = variant.OfferVariant2; ret.OfferVariant3 = variant.OfferVariant3; ret.OfferVariant4 = variant.OfferVariant4; ret.OfferVariant5 = variant.OfferVariant5; ret.OfferVariant1Type = variant.OfferVariant1Type; ret.OfferVariant2Type = variant.OfferVariant2Type; ret.OfferVariant3Type = variant.OfferVariant3Type; ret.OfferVariant4Type = variant.OfferVariant4Type; ret.OfferVariant5Type = variant.OfferVariant5Type; return ret; } 

I also shared the separation of columns into my own method, but it does nothing more than take an index and map values โ€‹โ€‹to an object, nothing special

Thanks again everyone, this will really weaken the code

+1
source

I assume that you just want to reduce duplicate code. In this case, just add the data as you know, and add the option at the end as soon as it is created. The only thing is that you need a copy constructor that copies values โ€‹โ€‹from previous runs.

 List<EtOfferVariant> variants = new List<EtOfferVariant>(); _containers[0].Variant.ForEach(first => { EtOfferVariant va = new EtOfferVariant(); va.OfferVariant1Type = _containers[0].VariantKey; va.OfferVariant1 = first; if (_containers.Count > 1) { _containers[1].Variant.ForEach(second => { va = new EtOfferVariant(va); va.OfferVariant2Type = _containers[1].VariantKey; va.OfferVariant2 = second; if (_containers.Count > 2) { _containers[2].Variant.ForEach(third => { va = new EtOfferVariant(va); va.OfferVariant3Type = third; va.OfferVariant3 = _containers[3].VariantKey; variants.Add(va); }); } else variants.Add(va); }); } else variants.Add(va); }); 

...

 public EtOfferVariant(EtOfferVariant va){ this.OfferVariant1Type = va.OfferVariant1Type; this.OfferVariant2Type = va.OfferVariant2Type; this.OfferVariant3Type = va.OfferVariant3Type; this.OfferVariant1 = va.OfferVariant1; this.OfferVariant2 = va.OfferVariant2; this.OfferVariant3 = va.OfferVariant3; } 
0
source

If you first convert dictionaries into containers, it seems you can get the desired result using the Cartesian product.

 var containers = new List<Dictionary<string, IEnumerable<string>>> { new Dictionary<string, IEnumerable<string>>() {{"Pie", new [] {"Raspberry", "Strawbery"}}}, new Dictionary<string, IEnumerable<string>>() {{"Drink", new [] {"Cola", "Coffee"}}}, new Dictionary<string, IEnumerable<string>>() {{"Bread", new [] {"Bagel", "Pretzel", "Scone"}}}, }; var flatten = containers.Select(dict => dict.SelectMany(c => c.Value.Select(v => new {type = c.Key, name = v}))); foreach (var combo in CartesianProduct(flatten)) { Console.WriteLine(string.Join(", ", combo.Select(c => c.type + ": " + c.name))); } 

Cartesian product method from fooobar.com/questions/9159 / ...

 public static IEnumerable<IEnumerable<T>> CartesianProduct<T>(IEnumerable<IEnumerable<T>> sequences) { IEnumerable<IEnumerable<T>> emptyProduct = new[] { Enumerable.Empty<T>() }; return sequences.Aggregate( emptyProduct, (accumulator, sequence) => from accseq in accumulator from item in sequence select accseq.Concat(new[] {item}) ); } 

Output:

 Pie: Raspberry, Drink: Cola, Bread: Bagel Pie: Raspberry, Drink: Cola, Bread: Pretzel Pie: Raspberry, Drink: Cola, Bread: Scone Pie: Raspberry, Drink: Coffee, Bread: Bagel Pie: Raspberry, Drink: Coffee, Bread: Pretzel Pie: Raspberry, Drink: Coffee, Bread: Scone Pie: Strawbery, Drink: Cola, Bread: Bagel Pie: Strawbery, Drink: Cola, Bread: Pretzel Pie: Strawbery, Drink: Cola, Bread: Scone Pie: Strawbery, Drink: Coffee, Bread: Bagel Pie: Strawbery, Drink: Coffee, Bread: Pretzel Pie: Strawbery, Drink: Coffee, Bread: Scone 
0
source

Source: https://habr.com/ru/post/974080/


All Articles