Ive been struggling to figure out what the correct way to do this is.
I have a table in Excel that relates Motor horsepower size to the amount of space it takes up.
I would like to implement a lookup function of this information in a C# Windows Form that I am writing.
I want to create a function that has a single argument passed to it (double HP). It would lookup if the motor HP falls in-between "Low" and "High" and then it would return the value in the "Space Factor" column. I feel pretty silly for not knowing the best way to do this. I want to avoid IF/Else statements as it doesnt seem like the right approach. Additionally, interfacing with Excel to do the lookup also seems a little silly.
How would you interface with a data table like this?
You should create an class to represent your rows, you can then add each object to a list. If you have few items you can just use Linq:
var hp = 20;
var objects = new List<MyClass>(){...};
var foundObj = objects.FirstOrDefault(o => hp > o.HpLow && hp < o.HpHigh);
if(foundObj != null){
// Found object!
}
If you have lots of rows you can instead sort the list by the HpHigh, and use BinarySearch to find the item without iterating over all items, but it requires a custom comparer and is a bit more complex.
If hp-ranges can overlap for you need some way to determine which of the rows is the most fitting one, so I'm just going to assume ranges do not overlap.
I would personally do this with c# arrays, however it might not be best or most practical solution for your solution, which im not quite sure how it works, however array is quick and easy to setup.
Related
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.
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.
I have a list and i have added my winform textboxes to it as shown below, but the list is 0 based, as the count starts from 0, how do i make it 1 based?
List<TextBox> textBoxList = new List<TextBox>();
textBoxList.Add(textBox1);
textBoxList.Add(textBox2);
textBoxList.Add(textBox3);
textBoxList.Add(textBox4);
textBoxList.Add(textBox5);
textBoxList.Add(textBox6);
textBoxList.Add(textBox7);
textBoxList.Add(textBox8);
textBoxList.Add(textBox9);
textBoxList.Add(textBox10);
textBoxList.Add(textBox11);
textBoxList.Add(textBox12);
I have an index which can be any number from 1 to 12, illd like to use this index to find the right textbox so index 6 will be textbox 6 .. rather than textbox 5
You cannot make .NET's list one-based, but you can either (1) adjust your index down by one every time you read, or (2) insert a useless entry at position 0 and ignore it after that (not recommended).
You can inherit from list, and build your own data structure that adjusts indexes on the way in and out, but that would require a lot more effort, not to mention the amount of confusion among the readers, so I would strongly caution against doing that.
Things don't do this way - list/array access is inherently zero-index based, and a custom implementation to attempt to defy this would be confusing (I personally think naming a class to be descriptive of its nature, if this were its nature, would be harder than doing the logic for a specific case elsewhere).
What's the use case? Usually you can get by with incrementing an index value to represent a 'current', or 'count' value that would make sense to users, or maybe adjusting input from a user perspective to what is needed, but what is your specific case?
If what you want to do, based on your update, is get a control by index you can either start your index from 0 or adjust the input as mentioned (by decreasing it according to the offset you need in the array) - this is just as easy, if not easier, and straightforward enough for anyone to understand, as any other method.
Maybe in your case it will be better to use Dictionary? So, your code will transform to:
Dictionary<int, TextBox> textBoxes =
new Dictionary<int, TextBox>();
textBoxes.Add(1, textBox1);
But anyway it's a strange requirement.
You can define your own list class which extends the built in class and insert the first element in the construct function.
One rather awkward way to solve your problem of making the collection index 1-based is to use the Array class. You can then create an array instance with arbitrary lower bound. In your case it would look like this:
var textBoxList = Array.CreateInstance(typeof(TextBox), new[] {12}, new[] {1});
Defining the elements in this array is somewhat more cumbersome:
...
textBoxList.SetValue(textBox5, 5);
...
And similarly, accessing the elements is also rather explicit:
var tb9ref = (TextBox)textBoxList.GetValue(9);
heres what i did and it seems to work :D, simple enough i guess.. still learning ..
var tb = textBoxList;
int newDef = def - 1;
tb[newDef].Text = "occupied";
Not long ago I posted a question about a design decision of my F1 game. One person replying noted my use of Dictionary<int, Driver> and asked what it was for. I use this collection for having a finish position and a Driver at that finish position. He suggested I should use arrays, because arrays have a index that could be used as position.
Having not worked on the game for a while, I picked up where I left and started to think about replacing my Dictionaries with arrays. I started googling arrays and one thing let to another and I came across posts here on SO, some blogs (http://blogs.msdn.com/b/ericlippert/archive/2008/09/22/arrays-considered-somewhat-harmful.aspx) about not to use arrays (or, actually, in some very specific cases).
My questions are these:
When data comes from the database, and is only used for comparing and looking up data, what is best used? I have a
prediction, which contains drivers and a predicted finish position
result, which also contains drivers and a finish position
points, which contains the points for every correctly guessed Driver at a certain finish position
The data comes from the database, and shouldn't be edited, added to, or removed.
The data is only used by my code only, but does that mean that I can safely use a collection, or should I really be on the safe side anyway and make sure that what comes back from the database is an immutable collection?
And the second question has to do with the positions. What collection can I use so that I can have finish positions, without maybe the overhead of using a Dictionary?
var prediction = new Driver[3];
prediction[0] = new Driver(10, "Michael Schumacher");
prediction[1] = new Driver(7, "Felipe Massa");
prediction[2] = new Driver(8, "Jensen Button");
var results = new Driver[3];
results[0] = new Driver(10, "Michael Schumacher");
results[1] = new Driver(8, "Jensen Button");
results[2] = new Driver(9, "Fernando Alonso");
int[] points = { 25, 18, 15, 12, 10 };
for (int i = 0; i < prediction.Length; i++)
{
if (prediction[i].Equals(results[i]))
{
result += points[i];
}
}
It depends on if you want to check by position (e.g. "Who finished third?") or by driver (e.g. "What position did Wilson finish at?"). It also depends on whether you care that much about performance in a scenario which sounds like it won't really make a difference to your application as a whole.
Generally a dictionary would be good for lookups. However, if the range of the keys is known, small, and continuous ("race position" fits all three criteria) then a dictionary does not offer anything more than an array (and has more overhead). So if you want to query by position, use an array because it's the simplest tool that fits the job description.
If you want to query by driver, then first you have to answer the question "how exactly is the identity of a Driver defined?" (an answer might be "each driver is uniquely identified by their last name, first name and date of birth").
You could then make the Driver class implement IEquatable<Driver> using these criteria and put it in a Dictionary<Driver, Positions> where I am using the class below to avoid multiple dictionaries.
class Positions
{
public int Predicted { get; set; }
public int Actual { get; set; }
}
However, you have to ask yourself if going to all this trouble makes any sense vs. having an array of e.g. Tuple<Driver, Positions> and looping over the array to find the driver you want each time. This may sound inefficient in theory, but if you have just 20 drivers it will actually be much faster than a dictionary.
Finally, I don't see any need in going out of your way to mark these data structures as immutable and/or enforce immutability. Since your application works in read-only mode, and it does not include code that attempts to push data back to the database, I think it's pretty clear that it's meaningless to go around modifying the data in code.
I use this collection for having a finish position and a Driver at
that finish position. He suggested I should use arrays, because arrays
have a index that could be used as position.
And for that case, he's pretty much right. An array is really the best way to do that because you know how many positions there are and the index acts as the position. It's going to use the least memory and get the most performance, and it's simple. I mean you could also use a List, which for this purpose is really just a fancier array.
There might be cases where arrays are "harmful", but there's also a case to be made that you should stick to simple tools when that's all you need to do the job. Arrays are simple, easily understood, and fast. When all you need is a Driver and a finish position, an Array is a perfect tool.
When data comes from the database, and is only used for comparing and
looking up data, what is best used? I have a
prediction, which contains drivers and a predicted finish position result, which also contains drivers and a finish position points,
which contains the points for every correctly guessed Driver at a
certain finish position
That depends. Do you want one collection that stores all of that information? If you do, Jon's suggestion of a Dictionary is probably your best bet. I suspect that's going to be a good way to go because it's got everything you need in a single place that you can work with.
If instead you want a different collection for each one, then for results and predicted results you can just use an Array for each one (as the data is perfectly suited for it). For points it's a bit different because the points aren't likely to be a perfectly set of index values and you could have two results with the same score.
I am writing an in-house application that holds several pieces of text information as well as a number of pieces of data about these pieces of text. These pieces of data will be held within a database (SQL Server, although this could change) in order of entry.
I'd like to be able to search for the most relevant of these pieces of information, with the most relevant of these to be at the top. I originally looked into using SQL Server Full-Text Search but it's not as flexible for my other needs as I had hoped so it seems that I'll need to develop my own solution to this.
From what I understand what is needed is an inverted index, then for the contents of said inverted index to be restored and modified based on the results of the additional information held (although for now this can be left for a later date as I just want the inverted index to index the main text from the database table/strings provided).
I've had a crack at writing this code in Java using a Hashtable with the key as the words and the value as a list of the occurrences of the word but in all honesty I'm still rather new at C# and have only really used things like DataSets and DataTables when handling information. If requested I'll upload the Java code soon once I've cleared this laptop of viruses.
If given a set of entries from a table or from a List of Strings, how could one create an inverted index in C# that will preferably save into a DataSet/DataTable?
EDIT: I forgot to mention that I have already tried Lucene and Nutch, but require my own solution as modifying Lucene to meet my needs would take far longer than writing an inverted index. I'll be handling a lot of meta-data that'll also need handling once the basic inverted index is completed, so all I require for now is a basic full-text search on one area using the inverted index. Finally, working on an inverted index isn't something I get to do every day so it'd be great to have a crack at it.
Here's a rough overview of an approach I've used successfully in C# in the past:
struct WordInfo
{
public int position;
public int fieldID;
}
Dictionary<string,List<WordInfo>> invertedIndex=new Dictionary<string,List<WordInfo>>();
public void BuildIndex()
{
foreach (int fieldID in GetDatabaseFieldIDS())
{
string textField=GetDatabaseTextFieldForID(fieldID);
string word;
int position=0;
while(GetNextWord(textField,out word,ref position)==true)
{
WordInfo wi=new WordInfo();
if (invertedIndex.TryGetValue(word,out wi)==false)
{
invertedIndex.Add(word,new List<WordInfo>());
}
wi.Position=position;
wi.fieldID=fieldID;
invertedIndex[word].Add(wi);
}
}
}
Notes:
GetNextWord() iterates through the field and returns the next word and position. To implement it look at using string.IndexOf() and char character type checking methods (IsAlpha etc).
GetDatabaseTextFieldForID() and GetDatabaseFieldIDS() are self explanatory, implement as required.
Lucene.net might be your best bet. Its a mature full text search engine using inverted indexes.
http://codeclimber.net.nz/archive/2009/09/02/lucene.net-your-first-application.aspx
UPDATE:
I wrote a little library for indexing against in-memory collections using Lucene.net - it might be useful for this. https://github.com/mcintyre321/Linqdex
If you're looking to spin your own, the Dictionary<T> class is most likely going to be your base, like your Java hashtables. As far as what is stored as the values in the dictionary, its hard to tell based on the information you provide, but typically search algorithms use some type of Set structure so you can run unions and intersections. LINQ gives you a much of that functionality on any IEnumerable, although a specialized Set class may boost performance.
One such implementation of a Set is in the Wintellect PowerCollections. I'm not sure if that would give you any performance benefit or not over LINQ.
As far as saving to a DataSet, I'm not sure what you're envisioning. I'm not aware of anything that "automagically" writes to a DataSet. I suspect you will have to write this yourself, especially since you mentioned several times about other third-party options not being flexible enough.