Closed. This question needs to be more focused. It is not currently accepting answers.
Want to improve this question? Update the question so it focuses on one problem only by editing this post.
Closed 2 years ago.
Improve this question
How can I make a working unit test for this code:
I want to test if there are 13 cards per color
I want to test if there are 4 cards per value
CODE:
public class CardSet
{
List<Card> cardset = new List<Card>();
public CardSet()
{
AddCardsToSet();
}
public Card CreateCard(CardValue cardValue, CardSuit cardSuit)
{
return new Card(cardValue, cardSuit);
}
public void AddCardsToSet()
{
for (int i = 0; i < 4; i++)
{
for (int z = 0; z < 13; z++)
{
cardset.Add(new Card((CardValue)z, (CardSuit)i));
}
}
}
public int ReturnSetSize()
{
return cardset.Count();
}
public List<Card> ReturnCardSetList()
{
return cardset;
}
}
ENUM 1
public enum CardSuit
{
Club,
Spade,
Heart,
Diamond,
}
ENUM 2
public enum CardValue
{
Two,
Three,
Four,
Five,
Six,
Seven,
Eight,
Nine,
Ten,
Jack,
Queen,
King,
Ace,
}
NOTE: it is not that easy as you think...would be happy if some of you have solution for that.
I will recommend at least writing your unit test scaffolding prior to my answering your question. Are you using MSUnit or some other test framework?
Below is an answer that should satisfy your criteria.
But, I will recommend the following:
split into separate test for suit count and value count
Add data driven parameter approach for VALUE or SUIT as parameter to run the same test method multiple times per parameter, so that in any failure we can identify which VALUE or SUIT is failing the test.
Sample:
//given
var cardsPerSuitCount = 13;
var cardsPerValueCount = 4;
//when
var myDeck = new CardSet();
foreach (var suitGrp in myDeck.cardset.GroupBy(x => x.cardsuit))
{
var suitCount = suitGrp.Count();
//then
//do your assert of cardsPerSuitCount vs suitCount here
}
foreach (var valueGrp in myDeck.cardset.GroupBy(x => x.cardvalue))
{
var valueCount = valueGrp.Count();
//then
//do your assert of cardsPerValueCount vs valueCount here
}
I am a blackjack fan.
The plan is;
Group all the cards by their suit and rank (I assume that the property names for these are Suit and Value in your code)
This will give us groups of distinct (suit,value) pairs each of which can have one or more cards under it. (having the same suit and value)
We expect all suits and values to fall in the range of our enums, so we check for this
And at the end, the test should succeed only if the number of groups is 52.
This guarantees that;
All the cards have suits between 0 and 3, and values between 0 and 12
There are no duplicate cards in the deck
There are exactly 52 cards in the deck
Using LinQ, this can be implemented as follows:
var deck = new CardSet();
var cardsInDeck = deck.ReturnCardSetList();
// preliminary simple check for null
Debug.Assert(cardsInDeck != null);
// preliminary simple check for card count
Debug.Assert(cardsInDeck.Count == 52);
// main assertion for the uniqueness and correctness of all the cards
Debug.Assert
(
cardsInDeck
.GroupBy(x => new { x.Suit, x.Value })
.Select(x =>
(int)x.Key.Suit >= 0 && (int)x.Key.Suit <= 3 &&
(int)x.Key.Value >= 0 && (int)x.Key.Value <= 12)
.Count() == 52
);
Related
Closed. This question needs to be more focused. It is not currently accepting answers.
Want to improve this question? Update the question so it focuses on one problem only by editing this post.
Closed 1 year ago.
The community reviewed whether to reopen this question 1 year ago and left it closed:
Original close reason(s) were not resolved
Improve this question
I have a List<List<int>>.
All the list will be of equal size. I need to find the max value in every index of the list.
ie if I have 100 list each of size 3. I need to find the max value at index 0,1 and 2 across the 100 items.
ie
Max value out of list1[0], list2[0], list3[0],......list100[0]
Max value out of list1[1], list2[1], list3[1],......list100[1]
Max value out of list1[2], list2[2], list3[2],......list100[2]
Need a function which accepts the List<List<int>> and returns an list with max value of each index. Like below
public List<int> FindMaxValueByIndex(List<List<int>> items)
{
}
Performance is a key factor that needs to be considered.
Ignoring data validation & guaranteeing the inner lists will always have the same number of elements:
public List<int> FindMaxValueByIndex(List<List<int>> items)
{
var maxListSize = items[0].Count;
var maxValues = new List<int>(items.Count);
for (var index = 0; index < maxListSize; index++)
maxValues.Add(items.Select(x => x[index]).Max());
return maxValues;
}
Input:
var data = new List<List<int>>
{
new List<int> { 5, 10, 300, 1 },
new List<int> { 3, 24, 2, 56 },
};
Output:
{5, 24, 300, 56}
I would recommend such approach using LINQ methods :)
private static int[] FindMaxByIndex(List<List<int>> lists)
{
var listLength = lists
.Select(x => x.Count)
.Distinct()
// If all lists are of equal length
// this should contain single element.
// Otherwise this would throw exception -
// this is validation.
.Single();
var maxesByIndex = new int[listLength];
for (int i = 0; i < listLength; i++)
{
maxesByIndex[i] = lists
.Select(x => x[i])
.Max();
}
return maxesByIndex;
}
I understand that the question states that the lists will always be the same size, however, since a generic list of generic lists is used and a generic list of generic lists does not enforce that requirement, this code takes the safe approach of ensuring that out of bounds indices are not accessed.
public List<int> FindMaxValueByIndex(List<List<int>> items)
{
List<int> ret = new List<int>();
var MaxListSize = items.Select(l => l.Count).Max();
for(int i = 0; i < MaxListSize; i ++)
{
ret.Add(items.Where(l => l.Count > i).Select(l => l[i]).Max());
}
return ret;
}
Fiddle
Closed. This question needs to be more focused. It is not currently accepting answers.
Want to improve this question? Update the question so it focuses on one problem only by editing this post.
Closed 2 years ago.
Improve this question
I have challenge to solve Sales by Match problem using c# without use List collection ?
*Alex works at a clothing store. There is a large pile of socks that must be paired by color for sale. Given an array of integers representing the color of each sock, determine how many pairs of socks with matching colors there are.
For example, there are N =7 socks with colors ar=[1,2,1,2,1,3,2] There is one pair of color 1 and one of color 2. There are three odd socks left, one of each color. The number of pairs is 2 .*
you can try this code
static int sockMerchant(int n, int[] ar) {
int matchingPairsCount= 0 ;
int[] arr =new int[n];
var ix=0;
for (int i = 0 ; i< ar.Length ; i++)
{
int countPairs = 0 ;
for(int j = 0 ;j< ar.Length ;j++)
{
if(ar[i] == ar[j] && i<j&& (!arr.Contains(i)|| i==0))
{
arr[ix]=j;
ix++;
matchingPairs = matchingPairs + 1 ;
break;
}
}
}
return matchingPairsCount;
}
You can use it using the following code
var ar = new int[] { 1,2,1,2,1,3,2 };
ar.GroupBy( g => g ).Sum( g => Math.Floor( g.Count() / 2.0 ) );
It groups all the items in the array first, and then sums up all pairs. You can try it here
This question already has answers here:
Select a random item from a weighted list
(4 answers)
Closed 4 years ago.
Is there a shorter way to check my random number from 1 - 100 (catNum) against this table of animals? This one doesn't look so bad but I have several more larger tables to work through, I would like to use less lines than I would have to using the statement below:
if (catNum < 36) { category = "Urban"; }
else if (catNum < 51) { category = "Rural"; }
else if (catNum < 76) { category = "Wild"; }
else if (catNum < 86) { category = "Wild Birds"; }
else { category = "Zoo"; }
Example of further tables:
I prefer to use something like this instead of many if/else
A category class
class Category
{
public int Min { get; set; }
public int Max { get; set; }
public string Name { get; set; }
}
Initialise categories once and fill it with your values
var categories = new List<Category>();
and finally a method to resolve the category
public static string Get(int currentValue)
{
var last = categories.Last(m => m.Min < currentValue);
//if the list is ordered
//or
// var last = categories.FirstOrDefault(m => m.Min <= currentValue && m.Max >= currentValue);
return last?.Name;
}
One alternative is to build up a full list of the items, then you can just select one, at random, by index:
var categories =
Enumerable.Repeat("Urban", 35)
.Concat(Enumerable.Repeat("Rural", 15))
.Concat(Enumerable.Repeat("Wild", 25))
.Concat(Enumerable.Repeat("Wild Birds", 10))
.Concat(Enumerable.Repeat("Zoo", 15))
.ToArray();
var category = categories[45]; //Rural;
Yes, this is a well-studied problem and there are solutions that are more efficient than the if-else chain that you've already discovered. See https://en.wikipedia.org/wiki/Alias_method for the details.
My advice is: construct a generic interface type which represents the probability monad -- say, IDistribution<T>. Then write a discrete distribution implementation that uses the alias method. Encapsulate the mechanism work into the distribution class, and then at the use site, you just have a constructor that lets you make the distribution, and a T Sample() method that gives you an element of the distribution.
I notice that in your example you might have a Bayesian probability, ie, P(Dog | Urban). A probability monad is the ideal mechanism to represent these things because we reformulate P(A|B) as Func<B, IDistribution<A>> So what have we got? We've got a IDistribution<Location>, we've got a function from Location to IDistribution<Animal>, and we then recognize that we put them together via the bind operation on the probability monad. Which means that in C# we can use LINQ. SelectMany is the bind operation on sequences, but it can also be used as the bind operation on any monad!
Now, given that, an exercise: What is the conditioned probability operation in LINQ?
Remember the goal is to make the code at the call site look like the operation being performed. If you are logically sampling from a discrete distribution, then have an object that represents discrete distributions and sample from it.
string[] animals = new string[] { "Urban", "Rural", "Wild", "Wild Birds", "Zoo" };
int[] table = new int[] { 35, 50, 75, 85 };
for (int catNum = 10; catNum <= 100; catNum += 10)
{
int index = Array.BinarySearch(table, catNum);
if (index < 0) index = ~index;
Console.WriteLine(catNum + ": " + animals[index]);
}
Run online: https://dotnetfiddle.net/yMeSPB
This question already has answers here:
c# check for a poker straight
(4 answers)
Closed 5 years ago.
I'm developing a poker game which works out what hand you have made given the cards dealt out. I'm currently stuck on the logic for the straight (5 cards in an incremental sequence e.g. 3,4,5,6,7). The Card objects I'm using have a int property which represents its value (ace is 14 by default).
Here's what I have so far:
private static bool CheckForStraight()
{
List<Card> tmpCards = new List<Card>(_cards); //local copy of the cards
if (tmpCards.Count < 5) //need atleast 5 cards to make a straight
return false;
tmpCards = tmpCards.DistinctBy(v => v.CardValue).ToList(); //remove duplicate values
tmpCards = tmpCards.OrderBy(x => x.CardValue).ToList(); //order list
int count = 0;
if (tmpCards.Zip(tmpCards.Skip(1), (a, b) => (a.CardValue + 1) == b.CardValue).Any(x => x))
{
count++;
}
else
{
count = 0;
}
return false;
}
When this code is run, the linq expression will check if any of the card values in the list are in sequence... so if the list contains cards with values 2,3,5,8,11 it would +1 to count as 2 and 3 are sequential. So count is always either going to be 0 or 1 which is no use to me. Ideally I'd want count to be 5 if there are five cards in sequence. Then if count was equal to 5, I could go on and find the cards that make the straight.
(Would be even better if a linq expression could determine which 5 cards were in sequence, not sure if that is possible in one expression mind).
My question: How can my current linq expression be modified to get the result I need? Or can I be pointed in the right direction if I'm going about this the wrong way, thanks in advance.
You're close - just check each card with the card 4 places after it and see if the difference is 4.
private static bool CheckForStraight()
{
List<Card> tmpCards = new List<Card>(_cards); //local copy of the cards
if (tmpCards.Count < 5) //need atleast 5 cards to make a straight
return false;
tmpCards = tmpCards.DistinctBy(v => v.CardValue).ToList(); //remove duplicate values
tmpCards = tmpCards.OrderBy(x => x.CardValue).ToList(); //order list
return tmpCards
.Zip(tmpCards.Skip(4), (a, b) => (a.CardValue + 4) == b.CardValue)
.Any(x => x);
}
You´re on a good track, now simply add a loop:
private static bool CheckForStraight()
{
List<Card> tmpCards = _cards.DistinctBy(v => v.CardValue).OrderBy(v => v.CardValue).ToList();
if(tmpCards.Count < 5) return false;
int count = 0;
for(int i = 1; i < tmpCards.Count; i++)
{
if(tmpCards[i] != tmpCards[i - 1] + 1 && count < 4) return false;
count++;
}
return count >= 5;
}
Closed. This question needs to be more focused. It is not currently accepting answers.
Want to improve this question? Update the question so it focuses on one problem only by editing this post.
Closed 8 years ago.
Improve this question
I have the following class:
internal class Course
{
public int CourseCode { get; set; }
public string DeptCode { get; set; }
public string Name { get; set; }
}
and the following code is the 2 dimensional array I have:
Course[][] courses = new Course[3][];
courses[0] = new Course[] {
new Course() { CourseCode = 100, DeptCode = "EGR", Name = "EGR A" },
new Course() { CourseCode = 100, DeptCode = "EGR", Name = "EGR B" }
};
courses[1] = new Course[] {
new Course() { CourseCode = 200, DeptCode = "EN", Name = "EN A" }
};
courses[2] = new Course[] {
new Course() { CourseCode = 300, DeptCode = "PHY", Name = "PHY A" }
};
What I want to do is get the different combinations that each item in a group could do with the other groups; for example with the previous code, the results would be:
1. EGR A - EN A - PHY A
2. EGR B - EN A - PHY A
Answers:
To get the number of combinations possible, we can use Rule of Product, in the above case, the possible combinations will be (2 * 1 * 1) = 2 which is indeed the 2 combinations I wrote above.
LordTakkera has given the perfect answer, thank you so much!
You could use a nested for loop:
for (int i = 0; i < courses[0].Length; i++)
{
for (int j = 0; j < courses[1].Length; i++)
{
for (int k = 0; k < courses[2].Length; i++)
{
//Do whatever you need with the combo, accessed like:
//courses[0][i], courses[1][j], courses[2][k]
}
}
}
Of course, this solution gets really messy the more nesting you need. If you need to go any deeper, I would use some kind of recursive function to traverse the collection and generate the combinations.
It would be something like:
class CombinationHelper
{
public List<List<Course>> GetAllCombinations(Course[][] courses)
{
return GetCourseCombination(courses, 0);
}
public List<List<Course>> GetCourseCombination(Course[][] courses, int myIndex)
{
List<List<Course>> combos = new List<List<Course>>();
for (int i = 0; i < courses[myIndex].Length; i++)
{
if (myIndex + 1 < courses.GetLength(0))
{
foreach (List<Course> combo in GetCourseCombination(courses, myIndex + 1))
{
combo.Add(courses[myIndex][i]);
combos.Add(combo);
}
}
else
{
List<Course> newCombination = new List<Course>() { courses[myIndex][i] };
combos.Add(newCombination);
}
}
return combos;
}
}
I tested this (substituting "int" for "Course" to make verification easier) and it produced all 8 combinations (though not in order, recursion tends to do that. If I come up with the ordering code, I'll post, but it shouldn't be too difficult).
Recursive functions are hard enough for me to come up with, so my explanation won't be very good. Basically, we start by kicking the whole thing off with the "0" index (so that we start from the beginning). Then we iterate over the current array. If we aren't the last array in the "master" array, we recurse into the next sub-array. Otherwise, we create a new combination, add ourselves to it, and return.
As the recursive stack "unwinds" we add the generated combinations to our return list, add ourselves to it, and return again. Eventually the whole thing "unwinds" and you are left with one list of all the combinations.
Again, I'm sure that was a very confusing explanation, but recursive algorithms are (at least for me) inherently confusing. I would be happy to attempt to elaborate on any point you would like.
Take a look at your second index - the 0 or 1. If you look only at that, you see a binary number from 0 to 7.
Count from 0 to 7, translate it to bits and get the combination pattern you need.