Some loop with conditions. Specific problem - c#

I have a small problem with mathematics or combinatorics in my C# code. I don't know how to write this easiest.
I have a class Section and TestClass but not a method to return expected result.
public class Section
{
public int Id { get; set; }
public int Pages { get; set; }
public string Name { get; set; }
}
[TestFixture]
public class PermutatorTest
{
private IList<Section> _sections;
private int _targetPage;
[SetUp]
public void SetUp()
{
_targetPage = 30;
_sections = new List<Section>
{
new Section {Id = 1, Pages = 15, Name = "A"},
new Section {Id = 2, Pages = 15, Name = "B"},
new Section {Id = 3, Pages = 10, Name = "C" },
new Section {Id = 4, Pages = 10, Name = "D"},
new Section {Id = 5, Pages = 10, Name = "E"},
new Section {Id = 6, Pages = 5, Name = "F"}
};
}
[Test]
public void GetPermutationsTest()
{
// Code to return list of all combinations
}
}
I want to get each combination which give me 30 as a sum of Pages.
it could be return as a string based on name or Id e.g AA or 11 , AB or 12
Of course, the order is not important ( AB and BA is the same... CCD and CDC and DCC too )
Final result should look like this: (30 correct results)
AA
AB
ACF
ADF
AEF
AFFF
BB
BCF
BDF
BEF
BFFF
CCC
CCD
CCE
CDD
CEE
CDE
CFFFF
CDFF
CCFF
CEFF
DDFF
DEFF
DFFFF
DDD
DDE
EFFFF
EEE
EEFF
FFFFFF
e.g. DDE = 10+10+10 = 30 OK
CFFFF = 10 + 5 +5 +5 +5 = 30 Ok
etc.
I dont have idea for best way to create loops for this, and put records to List
Thank you very much for every attempt to help me.

This was my original idea I was going to post for you, it just returned a list of strings
public List<String> result;
public void GetResultList(int startOffs, String CurNames, int curTotal)
{
for (int newOffs = startOffs; newOffs < _sections.Count; newOffs++)
{
int newTotal = curTotal + _sections[newOffs].Pages;
String newNames = CurNames+ _sections[newOffs].Name;
if (newTotal < _targetPage)
GetResultList(newOffs, newNames, newTotal);
else if (newTotal == _targetPage)
result.Add(newNames);
}
}
called by initialising the result & start parameters :
result = new List<String>();
GetResultList(0,"",0);
This is a version modified to use your Config class
public void GetResultList(int startOffs, Config CurConfig)
{
for (int newOffs = startOffs; newOffs < _sections.Count; newOffs++)
{
Config newConfig = new Config{ Name = CurConfig.Name + _sections[newOffs].Name,
Ids = CurConfig.Ids + _sections[newOffs].Id.ToString(),
Pages = CurConfig.Pages + _sections[newOffs].Pages};
if (newConfig.Pages < _targetPage)
GetResultList(newOffs, newConfig);
else if (newConfig.Pages == _targetPage)
_result.Add(newConfig);
}
}
calling needs the result initialising & a starting Config instance
_result = new List<Config>();
Config s = new Config { Ids = "", Pages=0, Name=""};
GetResultList(0,s);

Only for Information and Searchers.
I know, this code is not so clean
but I put it here as a nUnit Test...
it returns what I wanted ... i think.
using System;
using System.Collections.Generic;
using NUnit.Framework;
[TestFixture]
public class PermutatorTest
{
private IList<Section> _sections;
private int _targetPage;
private IList<Config> _result;
[SetUp]
public void SetUp()
{
_targetPage = 30;
_sections = new List<Section>
{
new Section {Id = 1, Pages = 15, Name = "A"},
new Section {Id = 2, Pages = 15, Name = "B"},
new Section {Id = 3, Pages = 10, Name = "C" },
new Section {Id = 4, Pages = 10, Name = "D"},
new Section {Id = 5, Pages = 10, Name = "E"},
new Section {Id = 6, Pages = 5, Name = "F"}
};
_result = new List<Config>();
}
[Test]
public void GetPermutationsTest()
{
for (var b =0 ; b<=_sections.Count-1; b++)
{
var config = new Config
{
Name = _sections[b].Name,
Ids = _sections[b].Id.ToString(),
Pages = _sections[b].Pages
};
GoDeeperAndAddToResult(config, b);
}
Console.WriteLine(_result.Count);
foreach (var item in _result)
{
Console.WriteLine($"{item.Name} - {item.Ids} - {item.Pages}");
}
}
private void GoDeeperAndAddToResult(Config config, int startIndex)
{
for (var b = startIndex; b <= _sections.Count-1; b++)
{
var section = _sections[b];
var combName = config.Name;
var combIds = config.Ids;
var combPages = config.Pages;
var maxSec = _targetPage / section.Pages;
for (var a = 1; a <= maxSec; a++)
{
combName = combName + section.Name;
combIds = combIds + section.Id.ToString();
combPages = combPages + section.Pages;
var subConfig = new Config
{
Name = combName,
Ids = combIds,
Pages = combPages
};
if (subConfig.Pages == _targetPage)
{
_result.Add(subConfig);
break;
}
else if (subConfig.Pages < _targetPage)
{
GoDeeperAndAddToResult(subConfig, b + 1);
}
else
{
break;
}
}
}
}
public class Config
{
public string Name { get; set; }
public string Ids { get; set; }
public int Pages { get; set; }
}
public class Section
{
public int Id { get; set; }
public int Pages { get; set; }
public string Name { get; set; }
}
}

Related

Sorting list with rules in C#

Tell me if there is a way to sort the list by the rules.
I have several playing decks and each has its own rules:
Count - how many cards to take from the deck
From / Before - in which interval the cards should be (If 0, then in any)
Row - how many cards can fall out in a row
My current code:
private void ShuffleDecks()
{
List<TestCard> testCards = new();
TestDesk desk1 = new TestDesk
{
From = 0,
Before = 0,
Row = 2,
Count = 3
};
desk1.Cards = new List<TestCard>
{
new("a1", desk1),
new("a2", desk1),
new("a3", desk1),
};
TestDesk desk2 = new TestDesk
{
From = 1,
Before = 4,
Row = 1,
Count = 2
};
desk2.Cards = new List<TestCard>
{
new("b1", desk2),
new("b2", desk2),
new("b3", desk2),
};
TestDesk desk3 = new TestDesk
{
From = 3,
Before = 5,
Row = 0,
Count = 2
};
desk3.Cards = new List<TestCard>
{
new("c1", desk3),
new("c2", desk3),
new("c3", desk3),
};
List<TestDesk> desks = new List<TestDesk> { desk1, desk2, desk3 };
foreach (TestDesk desk in desks)
{
desk.Cards.Shuffle();
testCards.AddRange(desk.Cards.Take(desk.Count).ToList());
}
testCards.Sort();
Debug.LogWarning($"{string.Join(", ", testCards.Select(x => x.Name))}");
}
TestDesk and TestCard:
public class TestDesk
{
public List<TestCard> Cards;
public int From;
public int Before;
public int Row;
public int Count;
}
public class TestCard
{
public string Name;
public TestDesk Desk;
public TestCard(string name, TestDesk desk)
{
Name = name;
Desk = desk;
}
}

Using where in LINQ select new statement for specific columns

I'm working on a class assignment and got a bit lost in LINQ.
I have 3 tables, 'oltandok' contains the data of persons, 'preferenciak' contains the preferred vaccine of that person with 3 columns:
an FK for table oltandok
a number indicating the order of preferences (1 is highest, 6 is lowest preferred)
an FK for another table containing the data on the vaccines called 'vakcinak'
I would like to display the data in a DataGridView the following way:
Personal data and the preferred vaccines in different columns:
Pref1 - Name of the vaccine where pref == 1
Pref2 - Name of the vaccine where pref == 2
etc.
This is where I am with my code, but I'm not sure how to select the preferences properly.
manu_rogz.DataSource = ( from x in context.oltandok
join y in context.preferencia on x.TAJ equals y.oltandok_FK
select new
{
TAJ = x.TAJ,
Nev = x.nev,
Szuletesnap = x.birthdate,
Pref1 = ???
Pref2 = ???
}
).ToList();
Because the preferenciak table contains multiple rows per person, you will need to perform some grouping.
Here is some very rough code which illustrates one way to do that.
using System;
using System.Collections.Generic;
using System.Linq;
class Program
{
static void Main(string[] args)
{
var persons = new List<Person> { new Person { ID = 11, PersonName = "Alice" }, new Person { ID = 22, PersonName = "Bob" } };
var vaccines = new List<Vaccine> { new Vaccine(){ ID = 111, VaccineName= "Pfizer" }, new Vaccine(){ ID = 222, VaccineName = "Moderna" } };
var preferences = new List<VaccPref>
{
new VaccPref() { Person_FK = 11, Preference = 1, Vaccine_FK = 111 },
new VaccPref() { Person_FK = 11, Preference = 2, Vaccine_FK = 222 },
new VaccPref() { Person_FK = 22, Preference = 1, Vaccine_FK = 222 },
new VaccPref() { Person_FK = 22, Preference = 2, Vaccine_FK = 111 }
};
var prefsWithVaccNames = preferences.Join(vaccines, p => p.Vaccine_FK, v => v.ID, (pref, vaccine) => new Tuple<VaccPref, string>(pref, vaccine.VaccineName));
var groupedPrefs = prefsWithVaccNames.GroupBy(p => p.Item1.Person_FK);
var personPrefs = new List<PersonPrefs>();
foreach (var group in groupedPrefs)
{
personPrefs.Add(
new PersonPrefs()
{
Person_FK = group.Key,
Pref1 = group.Single(v => v.Item1.Preference == 1).Item2,
Pref2 = group.Single(v => v.Item1.Preference == 2).Item2,
});
}
var personPrefsWithPersonNames =
personPrefs.Join(
persons,
pp => pp.Person_FK,
p => p.ID,
(pp, p) => new NamedPersonPrefs() { Name = p.PersonName, Pref1 = pp.Pref1, Pref2 = pp.Pref2 }).ToArray();
}
}
class Person
{
public int ID { get; set; }
public string PersonName { get; set; }
}
class VaccPref
{
public int Person_FK { get; set; }
public int Preference { get; set; }
public int Vaccine_FK { get; set; }
}
class Vaccine
{
public int ID { get; set; }
public string VaccineName { get; set; }
}
class PersonPrefs
{
public int Person_FK { get; set; }
public string Pref1 { get; set; }
public string Pref2 { get; set; }
}
class NamedPersonPrefs
{
public string Name { get; set; }
public string Pref1 { get; set; }
public string Pref2 { get; set; }
}
This is a self-contained C# program which should produce a result similar to what you're after. You will of course need to adjust the class definitions (and change the table names) to suit your needs.
I've used LINQ's fluent syntax but you can use the SQL-like version if you prefer.

NUnit DataSource from a different class

I am trying to make a test project using N Unit. I have everything working and now but i was wondering if it is possible to split the test cases into a completely separate class or would the only feasible way would be to push the data to a file or a partial class? basically I would like the data in a separate file instead of having all the data and the tests in one file. Or maybe that more of the standard and create different classes for each rule test.
[Test, TestCaseSource("TenantsRules")]
public void CheckDNQTenantsRules(DNQTenantData testData)
{
CoreServicesBroker.DNQCoreServiceBroker broker = new CoreServicesBroker.DNQCoreServiceBroker();
string actualDNQReason = string.Empty;
int actualReturnCode = broker.CheckDNQTenants(testData.FormCode, testData.StateCode, testData.EffectiveDate, testData.NumberOfTenants, ref actualDNQReason);
Assert.AreEqual(testData.ExpectedDNQReturnCode, actualReturnCode);
Assert.AreEqual(testData.ExpectedDNQReason, actualDNQReason);
}
public static IEnumerable<DNQTenantData> TenantsRules()
{
yield return new DNQTenantData() { FormCode = 9, StateCode = "OH", EffectiveDate = DateTime.Now, NumberOfTenants = 7, ExpectedDNQReturnCode = 1, ExpectedDNQReason = "Number of Tenants exceeded." };
yield return new DNQTenantData() { FormCode = 9, StateCode = "OH", EffectiveDate = DateTime.Now, NumberOfTenants = 5, ExpectedDNQReturnCode = 0, ExpectedDNQReason = "" };
}
I believe NUnits TestCaseData will solve your problem:
[TestFixture]
public class YourTest
{
[Test, TestCaseSource(typeof(YourTestCaseProvider), nameof(YourTestCaseProvider.TenantsRules)]
public void CheckDNQTenantsRules(DNQTenantData testData)
{
CoreServicesBroker.DNQCoreServiceBroker broker = new CoreServicesBroker.DNQCoreServiceBroker();
string actualDNQReason = string.Empty;
int actualReturnCode = broker.CheckDNQTenants(testData.FormCode, testData.StateCode, testData.EffectiveDate, testData.NumberOfTenants, ref actualDNQReason);
Assert.AreEqual(testData.ExpectedDNQReturnCode, actualReturnCode);
Assert.AreEqual(testData.ExpectedDNQReason, actualDNQReason);
}
}
public class YourTestCaseProvider
{
public static IEnumerable TenantsRules()
{
yield return new TestCaseData(new DNQTenantData() { FormCode = 9, StateCode = "OH", EffectiveDate = DateTime.Now, NumberOfTenants = 7, ExpectedDNQReturnCode = 1, ExpectedDNQReason = "Number of Tenants exceeded." })
yield return new TestCaseData(new DNQTenantData() { FormCode = 9, StateCode = "OH", EffectiveDate = DateTime.Now, NumberOfTenants = 5, ExpectedDNQReturnCode = 0, ExpectedDNQReason = "" });
}
}

Create dynamic XML class

I have a class "MsrProgram" that will serialize. However, if the parameter "Number" in "MsrProgram" is different, i need different parameters in my XML File. What is the easyest way to do somthing like this?
Here is my code:
public class MsrProgram
{
[XmlAttribute]
public string OwnerTypeFullName { get; set; }
[XmlAttribute]
public int Number { get; set; }
[XmlAttribute]
public int MsrRange { get; set; }
[XmlAttribute]
public int TurnoverMeasure { get; set; }
}
public class main
{
var toolList = (from pos in Configuration.List
select new Position
{
ToolNumber = (int)pos.tlno,
Tool =
{
ToolId = pos.tlno.ToString(),
Step =
{
Position = "1",
MsrProgram =
{
OwnerTypeFullName = "",
Number = 1,
MsrRange = "1", //When Number is 1
TurnoverMeasure = "1", //When Number is 2
}
}
}
}
}
Your code does not show everything so I can not give complete code, but this should get you going:
var toolList = (from pos in Configuration.List
select new Position
{
ToolNumber = (int)pos.tlno,
Tool = new Tool
{
ToolId = pos.tlno.ToString(),
Step = new Step
{
Position = "1",
MsrProgram = new MsrProgram
{
OwnerTypeFullName = "",
Number = GetNumber(), // <- fill in what really should be used
MsrRange = GetNumber() == 1 ? 1 : 0,
TurnoverMeasure = GetNumber() == 2 ? 1 : 0
}
}
}
}
);
I also added several new ... statements which you missed or forgot.

How to Insert a document with array of sub-documents by C# class

I'm amateur with mongodb and C# driver.
I try to Insert a document with array of sub-documents by class.
my codes are these:
This is my classes:
public class Entity
{
public string name { get; set; }
public string family { get; set; }
public List<sc> score { get; set; }
}
public class sc
{
public int Math{ get; set; }
public int literature{ get; set; }
}
And this is my code for fill fields and insert document:
var en = new Entity();
var sc1 = new sc();
var sc2 = new sc();
sc1.Math= 14;
sc1.literature= 15;
sc2.Math= 16;
sc2.literature= 19;
en.score[0] = sc1;
en.score[1] = sc2;
en.name = "Esi";
en.family = "Moja";
collection.Insert(en);
But i get this error when i run it:
Object reference not set to an instance of an object.
How can i fix this problem? Please help me.
This is because you don't initialize your list. Try this instead :
var en = new Entity();
var sc1 = new sc();
var sc2 = new sc();
sc1.Math= 14;
sc1.literature= 15;
sc2.Math= 16;
sc2.literature= 19;
en.score = new List<sc>(); // The missing line
en.score.Add(sc1); // How you add elements
en.score.Add(sc2); // in your list
en.name = "Esi";
en.family = "Moja";
collection.Insert(en);
You can also use an object initializer, for better readability :
var en = new Entity()
{
name = "Esi",
family = "Moja",
score = new List<sc>
{
new sc()
{
Math = 14,
Literature = 15
},
new sc()
{
Math = 16,
Literature = 19
}
}
}
collection.Insert(en);
you need to new up your list as it's null at the moment
en.score=new List<sc>();

Categories