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;
}
}
Related
I'm using MongoDb.Driver in C# to save information to my backend.
I've created a simple Repository to store a generic object:
public abstract class MongoRepository<TDocument> : IRepository<TDocument>
where TDocument : Entity
{
#region Private Fields
private readonly IMongoCollection<TDocument> _collection;
#endregion
#region Protected Properties
protected abstract String CollectionName { get; }
#endregion
#region Constructors
public MongoRepository(IMongoDbSettings settings)
{
IMongoDatabase? database = new MongoClient(settings.ConnectionString).GetDatabase("default");
_collection = database.GetCollection<TDocument>(CollectionName);
}
#endregion
#region Public Methods
public IQueryable<TDocument> AsQueryable()
{
return _collection.AsQueryable();
}
public IEnumerable<TDocument> FilterBy(
Expression<Func<TDocument, bool>> filterExpression)
{
return _collection.Find(filterExpression).ToEnumerable();
}
public IEnumerable<TProjected> FilterBy<TProjected>(
Expression<Func<TDocument, bool>> filterExpression,
Expression<Func<TDocument, TProjected>> projectionExpression)
{
return _collection.Find(filterExpression).Project(projectionExpression).ToEnumerable();
}
public async Task<TDocument> FindOne(Expression<Func<TDocument, bool>> filterExpression)
{
return await _collection.Find(filterExpression).FirstOrDefaultAsync();
}
public async Task<IEnumerable<TDocument>> Get()
{
IAsyncCursor<TDocument>? asyncCursor = await _collection.FindAsync(_ => true);
return await asyncCursor.ToListAsync();
}
public async Task<TDocument> Get(Guid id)
{
FilterDefinition<TDocument>? filter = Builders<TDocument>.Filter.Eq(doc => doc.Id, id);
return await _collection.Find(filter).SingleOrDefaultAsync();
}
public async Task Create(TDocument document)
{
await _collection.InsertOneAsync(document);
}
public async Task CreateMany(ICollection<TDocument> documents)
{
await _collection.InsertManyAsync(documents);
}
public async Task Update(TDocument document)
{
FilterDefinition<TDocument>? filter = Builders<TDocument>.Filter.Eq(doc => doc.Id, document.Id);
await _collection.FindOneAndReplaceAsync(filter, document);
}
public async Task Delete(Expression<Func<TDocument, bool>> filterExpression)
{
await _collection.DeleteManyAsync(filterExpression);
}
public async Task Delete(Guid id)
{
FilterDefinition<TDocument>? filter = Builders<TDocument>.Filter.Eq(doc => doc.Id, id);
await _collection.FindOneAndDeleteAsync(filter);
}
public async Task Delete(TDocument element)
{
await Delete(element.Id);
}
#endregion
}
Up until now it was working fine, but I first encounter the case of saving an object that has sub-objects and collections:
public class Dashboard : Entity//Entity has just a public Guid Id {get;set;}
{
public Guid OrganizationLevelId { get; set; }
public string Name { get; set; }
public bool IsShared { get; set; }
public Guid? OwnerId { get; set; }
public List<Widget> Widgets { get; } = new();
}
And now, when I'm trying to save a document that has a collection, the array of widgets isn't saved:
await _dashboardsRepository.Create(new Dashboard()
{
Name = "Default Dashboard",
IsShared = true,
Id = Guid.NewGuid(),
OrganizationLevelId = rootLevel.Id,
Widgets =
{
new Widget() {Columns = 2, Rows = 1, Y = 0, X = 0, Title = "Component 1"},
new Widget() {Columns = 1, Rows = 1, Y = 1, X = 0, Title = "Comp 2"},
new Widget() {Columns = 1, Rows = 1, Y = 1, X = 1, Title = "Comp 3"},
new Widget() {Columns = 2, Rows = 2, Y = 0, X = 1, Title = "Max 2x2", MaxItemsColumns = 2, MaxItemsRows = 2},
new Widget() {Columns = 2, Rows = 3, Y = 0, X = 4, Title = "Min 2x2", MinItemColumns = 2, MinItemsRows = 2},
new Widget() {Columns = 4, Rows = 2, Y = 2, X = 0, Title = "Component 6"},
new Widget() {Columns = 2, Rows = 2, Y = 3, X = 4, Title = "Component 7"}
}
}
)
I'm trying to keep some kind of separation of concern, so my business objects doesn't reference MongoDb.
I guess there is something to indicate that I want the child properties to be persisted but I can't find how, any idea?
I've resolved the issue. In fact there was no additional "serialization" required, but I did 2 changes:
My "Widgets" property was a
public List<Widget> Widgets{get;} = new List<Widget>()
After I transformed it to
public List<Widget> Widgets{get;set;}(and initialize the collection when creating a dashboard)
it works.
I'm not sure if it's because of the missing setter or the default initialization of the collection, but it works now.
I want to make addition using next object's property value in list.
Here is the sample code.
public class MyClass
{
public List<Model> modelList { get; set; }
public MyClass()
{
modelList = GetModelList();
}
public List<Model> GetModelList()
{
return new List<Model>
{
new Model(){Number = 1, Total = 0},
new Model(){Number = 2, Total = 0},
new Model(){Number = 3, Total = 0},
new Model(){Number = 4, Total = 0},
};
}
}
public class Model
{
public int Number { get; set; }
public int Total { get; set; }
}
In above case :
modelList[0].Total should be modelList[0].Number + modelList[1].Number
What could be the best way to achieve this ? Any help ?
Below is the code How I am achieving currently
for (int i = 0; i < modelList.Count - 1; i++)
{
modelList[i].Total = modelList[i].Number + modelList[i + 1].Number;
}
I added a method ComputeTotal to show a solution
public MyClass()
{
modelList = GetModelList();
modelList = ComputeTotal(modelList);
}
private List<Model> ComputeTotal(List<Model> models)
{
for (var i = 0; i < models.Count; i++)
{
var hasNext = (i + 1) < models.Count;
// no computation if hasNext is false
if (hasNext)
{
var currentNumber = models[i].Number;
var nextNumber = models[i + 1].Number;
models[i].Total = currentNumber + nextNumber;
}
}
return models;
}
i know this is very explicit. But it clearly demonstrates the approach.
Update:
added the hasNext check to avoid System.ArgumentOutOfRangeException: 'Index was out of range. Must be non-negative and less than the size of the collection.
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; }
}
}
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 = "" });
}
}
I want to create 3 methods, 2 to declare and initialize arrays. And 3rd to loop through the 2 arrays. I want to invoke the third method in main() to display each index of array2 grouped under array1 index. I hope I have put my question through clearly.
class Program
{
static void Main(string[] args)
{
Program p = new Program();
p.display(Carnivore, ZooMammals);
}
public void Mammals(ZooMammals[] category)
{
category = new ZooMammals[4];
category[1] = new ZooMammals() {Category="Carnivorous", Attribute = new Attributes[2] };
category[2] = new ZooMammals() { Category = "Carnivorous", Attribute= new Attributes[1] };
category[3] = new ZooMammals() { Category = "Carnivorous", Attribute = new Attributes[3] };
}
public static void Carnivore(Attributes[] Carn)
{
Carn = new Attributes[3];
Carn[0] = new Attributes() { Sex ="M", colour = "yellow",Name="Lion" };
Carn[1] = new Attributes() { Sex ="F", colour = "yellow",Name="Cat"};
Carn[2] = new Attributes() { Sex ="M", colour = "yellow",Name="Tiger"};
}
public static void display(Attributes[] Carn,ZooMammals[] category)
{
foreach (var a in category)
{
if (a == null) continue;
Console.WriteLine("{0},{1},{2}", a.Category, a.Attribute);
}
foreach (var x in category.Carn)
{
if (x == null) continue;
Console.WriteLine("{0},{1},{2}", x.Sex, a.colour, x.Name);
Console.WriteLine(category[1].Carn[0]);
Console.WriteLine(category[1].Carn[1]);
Console.WriteLine(category[1].Carn[2]);
Console.WriteLine(category[2].Carn[0]);
Console.WriteLine(category[2].Carn[1]);
}
Console.ReadLine();
}
}
public class Attributes
{
public string Sex;
public string colour;
public string Name;
}
public class ZooMammals
{
public string Category;
public Attributes[] Attribute;
}
}
static void Main(string[] args)
{
Program p = new Program();
p.display(Mammals(), Carnivore());
}
public ZooMammals[] Mammals()
{
ZooMammals[] category = new ZooMammals[4];
category[1] = new ZooMammals() {Category="Carnivorous", Attribute = new Attributes[2] };
category[2] = new ZooMammals() { Category = "Carnivorous", Attribute= new Attributes[1] };
category[3] = new ZooMammals() { Category = "Carnivorous", Attribute = new Attributes[3] };
return category;
}
public Attributes[] Carnivore()
{
Attributes[] Carn = new Attributes[3];
Carn[0] = new Attributes() { Sex ="M", colour = "yellow",Name="Lion" };
Carn[1] = new Attributes() { Sex ="F", colour = "yellow",Name="Cat"};
Carn[2] = new Attributes() { Sex ="M", colour = "yellow",Name="Tiger"};
return Carn;
}
This is where you are going wrong i feel. This can be done better by declaring two global arrays and just assigning values in the methods and using the same through out the code.