How to create an object based matrix in C#? - c#

Say I need to create a group of person's relationship matrix as following
x
Joe
Alice
Linda
Joe
-1
4
3
Alice
2
-1
3
Linda
3
3
-1
Using arraylists or MultiDimensional array is kinda confusing to looping and calculating to me, as I have to create another pair to bind each array index to the person's object. just wondering if there's any better way to access/modify values in such matrix structure, tks
Edit:
To be more clear, I'm wondering if there's any existing libraries to help making such matrix easier, my main issue to use multiDimensional arr[row,col], then bind it with Person's list requires some additional works to structure it properly. If something like [Joe,Alice], [Linda, Joe] out of box would make my life easier, lol
at last, it is my C# skill to be blamed :(

Related

Can you use ML.NET to train models that use jagged arrays as training data?

Background:
I have experience implementing TensorFlow models in dotnet using TensorFlow.Net, and the models I use are trained in python/TF and generally take in multidimensional arrays and return multidimensional arrays. I want to do something similar, but purely using ML.Net.
The question:
I want to do a little solo fun project which takes in a jagged array and returns a jagged array. All of the documentation and tutorials I have watched only give examples of training data using strings or singles. Am I barking up the wrong tree, attempting to do this in ML.NET? I'm not asking anyone to do the work for me, but if someone could point me towards resources/documentation relating to model training using jagged/multidimensional arrays, I'd be very grateful!
Further info:
My intended project is a noughts and crosses (tic-tac-toe) model which takes in the current state of the board in the format: short[rows: 3][columns: 3] and returns the next state of the board, also in the format short[3][3]
example input:
[1,-1,0],[1,-1,-1],[-1,-1,-1]
where 1 is an 'x', 0 is a '0' and -1 is an empty grid space.
The model should then return the state of board once it has made its move
example output:
[1,-1,0],[1,-1,-1],[0,-1,-1]
ML.NET currently does not support multidimensional arrays. However, if you flattened that array into a 1D array / vector. It's possible.
This documentation shows a sample using VectorType which effectively is a float[]
https://learn.microsoft.com/dotnet/machine-learning/how-to-guides/load-data-ml-net#annotating-the-data-model-with-column-attributes

Grouping neighbouring entries with the same value in a 2d array

EDIT: I now realized the question was not appropriate for stack but I've gotten a lot of helpful advice anyway. Thanks everyone!
I have a 2d array and I want to group together neighbors of the same value. Using C# (working with unity).
Let's say I have this:
int[,] array {
0,0,0,0,0,0,1,0,0,0,
0,1,1,0,0,0,1,0,0,0,
0,1,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,1,1,1,0,
0,0,0,0,0,0,1,1,1,0
}
There are three "clusters" of 1:s. I want to add them to a dictionary with some variable for identification. So maybe first add the neighboring values to a list, add that list to a dictionary, clear the list and move onto the next cluster.
The columns and rows would be of equal length in the real thing.
I would also want the sorting method to accept arrays of various sizes so no hardcoded values. I parse the array from an XML document.
I've tried looking into Array.Sort but the resources I have found have been exclusively about sorting values in as/descending order. Just pointing me in the right direction, some some relevant web resources would be greatly appreciated!
I'm not going to give you the answer in full code since 1. you shouldn't be asking for it here and 2. you can definitely work it out yourself.
This is a good opportunity for you to whip out your pen and paper and figure out the algorithm. Lets say we want something similar to your task: just grouping the clusters of ones. The pseudocode might look like this.
Create a list of clusters
For each element in the grid, check if its a one.
If it is a one, check if it has a neighbor that is part of a cluster.
If so, add it to that cluster, else create a new cluster an add it.
If would then run through this on paper with a small example.
Once you have your desired algorithm, putting it into a dictionary and sorting it should be trivial.

Finding same adjacent values in 2D array, returning number of values

I am making a game, somewhat similar to connect 4, in that the aim is to connect same values in a grid. However, differently from connect 4, the connected values do not have to be in one straight line. For example:
0000
0100
0111
Where "1" is an item dropped by the player, I need to make an algorithm to tell me how many connections were made (4), and where on the grid.
Whether you can point me in the right direction for where to look, give advice or even code, I appreciate all and any help! :)
Btw I'm making this program in C#, so any language specific stuff has gotta be for that
THANKS "The Javatar" :) seems to work
This is a classic Fill algorithm. There are two ways you can implement it. Either with a recursive method or using queue (being equivalent to DFS / BFS traversal of a graph).
Here are all the information you would need for implementing it :)
https://en.wikipedia.org/wiki/Flood_fill

Preparing Accelerometer Data for SVM

I am trying to classify activities by feeding the acceleration data from my phone into a SVM, which I'm implementing in C# with Accord. The problem is that I don't know how to prepare the data.
One of the Problems is that the SVM seems to only take 2 dimensional Input, but the data I get has 3 Dimensions of course. Do I have to transform the Data somehow first?
The second Problem I have is that I get the data like following:
1 x:1502 y:2215 z:2153
1 x:1667 y:2072 z:2047
1 x:1611 y:1957 z:1906
2 x:1904 y:2367 z:2034
2 x:1905 y:2375 z:2023
2 x:1892 y:2379 z:2027
But I can't classify an activity by one row, since that is only a snapshot, only one frame while the activity is performed. So my guess is that it should look more something like this:
1 {x:1502 y:2215 z:2153}, {x:1667 y:2072 z:2047}, {x:1611 y:1957 z:1906}
2 {x:1904 y:2367 z:2034}, {x:1905 y:2375 z:2023}, {x:1892 y:2379 z:2027}
And then again, how can i feed this kind of data to my SVM?
Thanks in advance :)
Yes you can, it is called a sequence in classification.
To do that you can use Hidden Markov Classifier or Hidden Conditional Random Field Learning or a Dynamic Time Warp Support Vector Machine.
See Accord.net wiki section "Sequence classification"

Using Lookup or Dictionary to represent a hand of cards in C#

I apologize if there is a similar question already out there. There
are several questions about scoring hands but I don't need that.
The project I am working on takes in 10 cards and needs to report the
best possible 5-card hand found ("straight", "high card", "flush"
etc.). Luckily what the actual hand of cards is is irrelevant, I just
need a name.
I've already parsed and sorted all the cards out and have the tests
for all the possible hands laid out. All I need now is a convenient
way to store the hands. My mad method is as follows, in pseudocode
terms:
I want to have a dynamic list horizontally that I can populate with the NUMBER values of the cards, in order from highest to lowest. For
example, "Q J T 7 4 2 1". T is 10. Duplicates of values will be
ignored. Next, I want each of those values to have, underneath, a
list of the suits of each value that exist in the deck. For example,
J will have a sub-list with the values "D H" to represent that I have
a Jack of Diamonds and a Jack of Hearts.
I believe this to be the most elegant way to deal with these cards,
since most poker hands deal with only values and this way I don't have
to worry about cards of the same value in a row for say the straight
test. Then the two tests that do deal with suit can easily be
tested for by referring to the values under the keys.
Take a deep breath, almost there.
So an instance of Lookup appears to be perfect! It has the exact "one
key to multiple values" structure that I want. However, it doesn't
allow me to add the suits as I come to them. I have to add them all
at once or not at all since the lists are immutable after entry.
So I either
have to find all the suits at once before I even make the Lookup
Somehow add values to the Lookup lists or
Use something else.
Any ideas on any of these?
UPDATE
TL;DR SPARKNOTES VERSION: How can I add more values to the keys inside of a Lookup?
*IMOPRTANT NOTE:*The output of this program should be a string containing the name of the highest hand possible, for example "four of a kind", "two pair" or "high card."
I found one solution (which I unfortunately lost the link to and can't find again) where they suggested re-creating the entire Lookup with the new list. It may just be me but I find that solution to be very... ugly... Anyway several other solutions I have explored or tested are to:
METHOD 1
Roll through and populate another array with the suits associated with each value. Basically (in actual pseudocode this time >_>):
Create an array of ArrayLists (array 1)
Iterate through a sorted string array of "cards" (array 2)
For each card:
Take the char at string index [1] (representing the suit) and add into the ArrayList in array 1 at the index number extracted from string index [0].
This way I have the list of values with associated suits that I wanted. And the list of suits is the minimal size to boot, making iteration through that easier later. With some extra steps I can even make the umbrella array an ArrayList and populate it with the card values in order so there are no gaps and no duplicate numbers. This will leave me with a jagged array of what I want. To be clear, this is not a homework assignment. However, it IS from a coding class project my roommate completed in the past which is why I have the constrictions and requirements I have. Someone else I asked told me SE gets plagued by these kinds of homework questions around this time, so I understand your skepticism. This is a personal project because I want to learn C# (all I know is Java right now, and I like the sound of parameter pointer passing in C# methods, which Java does not do).
If it WERE for a grade I would end there because it works. But I don't really like arraylists of arraylists, they seem messy to me. So I want to know if there is another method.
METHOD 2
I also considered simply dealing with duplicates that inevitably appear. For example, here is my test for a straight:
for (int i = 0; i < 5; i++)
{
int counter = 0;
for (int j = i; j < i + 4; j++)
{
int secondCard = getValue(cardsArray[j + 1]);
int firstCard = getValue(cardsArray[j]);
if (secondCard == firstCard)
{
break;
}
if (secondCard == (firstCard + 1))
{
counter++;
if (counter == 4)
{
isStraight = true;
return "straight";
}
}
}
}
This code does not work. It needs some tweaks somewhere or other to work completely but I want to analyze if it is worth it before I try to fix it. It DOES accurately test for a straight, though. Also a couple notes: firstCard and secondCard are there for readability and debug purposes, and isStraight is there so that I don't reinvent the wheel later when I test for a straight flush.
This nested loop will iterate through all the cards up till the 5th card (since you can't have a straight out of ten sorted cards with less than 5 cards) and then check the next five cards as you would expect. If during this iteration I encounter a duplicate entry it means that it's the same card of another suit and I simply "break". What SHOULD happen as a result of this one statement is that now we have incremented our second iteration by one to check the next card instead of the current one. The count of in-order cards that we have will stay the same so that a list like " 1D 2D 3S 3H 4D 5C" will skip over the second 3 when finding the straight. Despite the break I was actually quite pleased with the elegance of this solution, whether I had a right to be or not.
It all goes back to the flaws of using a simple array of strings ("cards"), which is what my code is tailored to right now. And I hate fixing issues, I'd rather avoid them. Maybe I'm being unnecessarily picky but I'm learning along the way.
METHOD 3
My consideration of the weaknesses of an array of strings lead me to Dictionaries, which looked attractive. It can easily be made to hold my values in order, and easy to find if I have a certain suit for a key (TryGet), all in a neat, tailor-made package. Creating multiple array lists and doing things like "(find index of my value); array1[index].Add(value)" would be replaced by "Dictionary.Add(value, suit)". But I can only add a suit to a key at the point of creation. I couldn't make a "2" key and add "S" and then when I find out the next card is a "2D" add a D under the "2" key. Dictionary just doesn't support that, or even adding multiple values at all. I can make a dictionary of lists, but I still can't edit the list since Dictionaries are mostly query data structures. Lookups support multiple values per key but still cannot be changed after the initial "Add()". Again I could "re-create" the entire lookup or dictionary to add a suit and keep everything in order. But to me that seems like rebuilding the whole bridge because this one cable is too long and I don't have an industrial able cutter. It's a problem that SHOULD have an easier solution, like maybe go and GET some cutters (import a class maybe?).
CONCLUSION
Since you suggest that my needs are no different than what a hand scoring system could deliver leads me to another question:
Are hand scores directly tied to certain hands? Like I mentioned earlier the result I want is "The best hand you can make is a full house" not "This player has the highest hand." So can I calculate the highest scoring hand and extrapolate a "full house" from that score? If so then I guess this is all unnecessary code, but I would kind of like to solve this anyway in that case.
As I wrote this edit it dawned on me that this is basically a vanity issue. I don't "like" the solution I have. I also don't want to use the accepted solution (table lookup) because that is not a coding project that is a copypaste project. I would greatly appreciate any input.
Let's do this the simplest way possible. First, say you have an array of 10 strings, each of which is the name of a card. Like "Four of Hearts" and "Queen of Spades". That's really inconvenient to work with. So the first thing we do is convert those strings to numbers to represent each card. A very convenient way to do it is to use numbers 0-12 for hearts, 13-25 for diamonds, etc. So you have code (possibly a lookup table) that converts names to numbers:
Ace of Hearts = 0
Two of Hearts = 1
Three of Hearts = 2
...
Queen of Hearts = 11
King of Hearts = 12
Ace of Diamonds = 13
...
...
Ace of Clubs = 26
...
...
Kind of Spades = 51
So you have an array of numbers that represents the 10 cards. Call it cardsArray:
int[] cardsArray = new int[10];
// here, fill the cards array from the input
It's easy to check for flushes if you sort by suit and value. Remember, there are only 10 cards, so sorting isn't going to take a huge amount of time. The sort is really easy:
int[] sortedBySuit =
cardsArray
.OrderBy(x => x/13) // sorts by suit
.ThenByDescending(x => x % 13) // then by value, descending
.ToArray();
You can then go sequentially through the array and determine if you have a flush, straight flush, and what the high card in the flush (if any) is.
You have to save that information, because four-of-a-kind beats a flush, for example. So you need to check that, too.
Next, sort by value:
int[] sortedByValue =
cardsArray
.OrderByDescending(x => x % 13)
.ToArray();
Now you can go sequentially through that list to determine high card, pairs, three of a kind, four of a kind, or straights. As you find each type of hand, you save that hand information ("king high straight" or "three tens", along with the hand's value [1 for high card, 2 for pair, straight, flush, full house, etc. in the proper order]) to a list.
Then you just pick the hand with the highest value from those that you found.
That's definitely not the fastest way to do things, but it's simple, uses very little memory, and is fast enough for a prototype. It's certainly simpler than using a dictionary or array of arrays, etc.
To be clear, I didn't read your novel.
TL;DR SPARKNOTES VERSION: How can I add more values to the keys inside of a Lookup?
Usually, when I need a "dictionary" with a key that has multiple values, I use a List<KeyValuePair<string, int>>. You could use LINQ to Objects to select all the values. For example:
static void StackOverflowExample()
{
var cardList = new List<KeyValuePair<string,int>> ()
{
new KeyValuePair<string, int>("Club", 8),
new KeyValuePair<string, int>("Spade", 9),
new KeyValuePair<string, int>("Heart", 10)
};
var results = cardList.Where(p => p.Key == "Heart");
}
var results is an IEnumerable<KeyValuePair<string,int>>. Hopefully, this helps.

Categories

Resources