How to set string values into an enumerator - c#

I have one string that contains integers and strings, separated by a comma.
For example:
0, Link Alive,1, Link Dead,2, Link Weak,3, Wiznet 0 Dead,4, Wiznet 1 Dead,5, Wiznets Dead
I want to make an enum out of this string like this:
public enum myEnums {
Link Alive = 0,
Link Dead = 2,
Link Weak = 1,
Wiznet 0 Dead = 3,
Wiznet 1 Dead = 4,
Wiznets Dead = 5
}
I was thinking about changing the string into a char array. After that I loop through the char array.
If I detect an integer, I assign its value to a temporary integer value. If I detect a string, I assign its value to a temporary string. After this I'll assign the temporary integer and string to an enumerator.
Only thing is, I don't know how to deal with the comma and the equal sign.
Can someone show me how it's supposed to be done?

It sounds to me like what you really ought to be doing is creating a Dictionary<string,int> since unless you are going to generate code, you can't change an enum at runtime, it's constant.
Now looking at your string:
0, Link Alive,1, Link Dead,2, Link Weak,3, Wiznet 0 Dead,4, Wiznet 1 Dead,5, Wiznets Dead
It looks like you have a set of comma delimited values. So split on , and then each pair of values is an int and a string. Make that you dictionary.
So a simple way to do that might look like this (assuming your data is good, i.e. it has a even number of items and every odd item actually can be parsed as an int):
var dict = new Dictionary<int,string>();
var cells = source.Split(',');
for (var i=0; i < cells.Length; i+=2)
{
dict[int.Parse(cells[i])] = cells[i+1].Trim(); // Note: you might want to check boundaries first!
}
Or using Linq, you could do something like this:
string source = "0, Link Alive,1, Link Dead,2, Link Weak,3, Wiznet 0 Dead,4, Wiznet 1 Dead,5, Wiznets Dead";
var dict = source.Split(',')
.Select((v,i) => new { v, i })
.GroupBy(x => x.i/2)
.ToDictionary(x => int.Parse(x.First().v), x => x.Skip(1).First().v.Trim());
Here's a fiddle.
To explain what we are doing here:
First with Split your string on ,. This give us a string array with ["0","Link Alive","1","Link Dead",...]
Next we use Select to select each item and it's index in a pair. So now we have a collection of objects that looks something like [{v="0",i=0},{v="Link Alive",i=1},...]
Now we group this by dividing the index by 2. Because this is integer division, it will truncate. So 0/2 == 0 and 1/2 == 0 and 2/2 == 1 and 3/2 == 1. So we are sorting into pairs of values.
Finally we convert these groups (which we know are pairs of values) into a dictionary. To do that we use the first item in each group and parse it into an int and use that as the key for our dictionary. Then we use the second value as the value. This finally gives us our dictionary
Now with you dictionary, if you want to look up a value, it's easy:
var myValue = dict[2]; // myValue is now "Link Weak"

By enumerator I assume you mean something over which you can iterate. An 'enum' is basically a set of named integers.
So if you have a string of items separated by commas and want to 'iterate' over them, then this may help:
string input = "0, Link Alive,1, Link Dead,2, Link Weak,3, Wiznet 0 Dead,4, Wiznet 1 Dead,5, Wiznets Dead"
string[] parts = input.split(new char[] {','}, StringSplitOptions.RemoveEmptyEntries);
foreach (string part in parts)
{
// do something
}

Related

Converting a number with 000 and a -1 to its positive representation with only one 0

Read a list of non-negative integer values, sentinel -1 (i.e. end the
program and display the output), and print the list replacing each
sequence of zeros with a single zero.
Example input
100044022000301-1
Then the output will be:
10440220301
the last problem of my list, I don't have a clue how to solve it, I tough in removing the zeros and transforming then in than adding a 0 after that
feels bad
Something like this: Linq (in order to take the value before sentinel -1) and Regular expressions (turn 2 or more consequent 0 into single 0):
given a list we can find out the last value before sentinel as
var value = list
.TakeWhile(item => item != sentinel)
.Last();
to turn two or more consequent 0 into single one we can use Regex:
string removed = Regex.Replace(value.ToString(), "0{2,}", "0");
Code:
// initial " list of non-negative integer values"
// I've declared it as long, since 100044022000301 > int.MaxValue
List<long> list = new List<long>() {
4555223,
123,
456,
100044022000301L, // we want this value (just before the sentinel)
-1L, // sentinel
789,
};
long result = long.Parse(Regex.Replace(list
.TakeWhile(item => item != -1) // up to sentinel
.Last() // last value up to sentinel
.ToString(),
"0{2,}", // change two or more consequent 0
"0")); // into 0

Get IndexOf Second int record in a sorted List in C#

I am having problem while trying to get First and Second Record (not second highest/lowest integer) Index from a sorted List. Lets say that list consists of three records that in order are like this: 0, 0, 1.
I tried like this:
int FirstNumberIndex = MyList.IndexOf(MyList.OrderBy(item => item).Take(1).ToArray()[0]); //returns first record index, true
int SecondNumberIndex = MyList.IndexOf(MyList.OrderBy(item => item).Take(2).ToArray()[1]); //doesn't seem to work
As I explained, I am trying to get the indexes of first two zeros (they are not necessarily in ascending order before the sort) and not of zero and 1.
So if there was a list {0, 2, 4, 0} I need to get Indexes 0 and 3. But this may apply to any number that is smallest and repeats itself in the List.
However, it must also work when the smallest value does not repeat itself.
SecondNumberIndex is set to 0 because
MyList.OrderBy(item => item).Take(2).ToArray()[1] == 0
then you get
MyList.IndexOf(0)
that finds the first occurence of 0. 0 is equal to every other 0. So every time you ask for IndexOf(0), the very first 0 on the list gets found.
You can get what you want by using that sort of approach:
int FirstNumberIndex = MyList.IndexOf(0); //returns first record index, true
int SecondNumberIndex = MyList.IndexOf(0, FirstNumberIndex + 1 ); //will start search next to last ocurrence
From your code I guess you confuse some kind of "instance equality" with regular "equality".
Int is a simple type, IndexOf will not search for ocurrence of your specific instance of 0.
Keep in mind that this code, even if we will move in our thoughts to actual objects:
MyList.OrderBy(item => item).Take(2).ToArray()[1]
will not necessarily return equal objects in their original relative order from the input list.
EDIT
This cannot be adopted for general case, for getting indexes of ordered values from the original, unordered list.
If you are searching for indexes of any number of equal values, then setting bigger and bigger offset for the second parameter of IndexOf is OK.
But, let's consider a case when there are no duplicates. Such approach will work only when the input list is actually ordered ;)
You can preprocess your input list to have pairs (value = list[i],idx = i), then sort that pairs by value and then iterate over sorted pairs and print idx-es
You, probably, are asking about something like this:
var list = new List<int>{0,0,1};
var result = list.Select((val,i)=> new {value = val, idx = i}).Where(x=>x.value == 0);
foreach(var r in result) //anonymous type enumeration
Console.WriteLine(r.idx);
You can try user FindIndex.
var MyList = new List<int>() {3, 5, 1, 2, 4};
int firsIndex = MyList.FindIndex(a => a == MyList.OrderBy(item => item).Take(1).ToArray()[0]);
int secondIndex = MyList.FindIndex(a => a == MyList.OrderBy(item => item).Take(2).ToArray()[1]);
You could calculate the offset of the first occurrence, then use IndexOf on the list after skipping the offset.
int offset = ints.IndexOf(0) + 1;
int secondIndex = ints.Skip(offset).ToList().IndexOf(0) + offset;

How to split string and convert to int

Basically lets say I have used this:
string[] result = File.ReadAllText("C:\\file.txt");
Inside the .txt file is the following words/values (case sensitive):
Zack 2 5 5
Ben 5 3 4
Dom 2 4 6
Currently I know whatever is read will be stored in the string array and it includes the name and numbers.
How do I split them so that the names are in one array and the numbers are converted into int array? Basically separating the numbers and names.
Loop over each item, split by space, use the first value as a key, then use the rest of the values to create array of ints.
string[] result = { "Zack 2 5 5", "Ben 5 3 4", "Dom 2 4 6" };
var lookup = result.ToDictionary(
key => key.Split(' ').First(), // first is name, ignore rest
ints => ints.Split(' ')
.Skip(1) // skip the name, ints are the rest
.Select(i => int.Parse(i))
.ToArray());
foreach (var kvp in lookup)
Console.WriteLine(kvp.Key + " - " + string.Join(",", kvp.Value));
Output:
Zack - 2,5,5
Ben - 5,3,4
Dom - 2,4,6
I used Dictionary as the generated list. That's assuming that every item in the result array has a unique name value. If there are duplicates, you'll need to modify it to either append the new int values or use something else than a dictionary to keep your parsed values.
You can see this SO thread about the case-sensitivity of dictionaries (they arn't).
For chars array:
string charsArray = new String(result.ToCharArray().Where(c => Char.IsLetter(c)).ToArray());
For numbers array;
string NumbersArray = new String(result.ToCharArray().Where(c => Char.IsDigit(c)).ToArray());
Decide just when and how to use them. good luck
one way of use is per row.

How to store the last few numbers as a variable in a table row

If I have a table , with row with numbers like 70-0002098, lets just call the row, ID
I need the last 4 numbers for all the table rows,
So what I need is something like
foreach(var row in table)
{
var Id = row.ID(but just the last 4 digits)
}
Not sure what format you want to store it as, or what you want to do with it after, but...
Edit: Added an if check for length to avoid index out of bounds condition. Also corrected syntax- SubString() => Substring()
int count = 0;
foreach(var row in table){
string temp = row.ID.ToString();
count += (temp.Length > 5)? Convert.ToInt32(temp.Substring(temp.Length-5, 4)) : Convert.ToInt32(temp);
}
// But I have no idea what datatype you have for that or what
// you want to do (count up the integer values or store in an array or something.
// From here you can do whatever you want.
Your illustration suggests that the RowID is not currently a number (its got a hyphen in it) so I assume its a string
id.Right(4);
will return the right four characters. It doesn't guarantee they are numbers though. Right is an extension method of string which can be easily written, or copied from this thread Right Function in C#?

Bag of Words representation problem

Basically i have a dictionary containing all the words of my vocabulary as keys, and all with 0 as value.
To process a document into a bag of words representation i used to copy that dictionary with the appropriate IEqualityComparer and simply checked if the dictionary contained every word in the document and incremented it's key.
To get the array of the bag of words representation i simply used the ToArray method.
This seemed to work fine, but i was just told that the dictionary doesnt assure the same Key order, so the resulting arrays might represent the words in different order, making it useless.
My current idea to solve this problem is to copy all the keys of the word dictionary into an ArrayList, create an array of the proper size and then use the indexOf method of the array list to fill the array.
So my question is, is there any better way to solve this, mine seems kinda crude... and won't i have issues because of the IEqualityComparer?
Let me see if I understand the problem. You have two documents D1 and D2 each containing a sequence of words drawn from a known vocabulary {W1, W2... Wn}. You wish to obtain two mappings indicating the number of occurrences of each word in each document. So for D1, you might have
W1 --> 0
W2 --> 1
W3 --> 4
indicating that D1 was perhaps "W3 W2 W3 W3 W3". Perhaps D2 is "W2 W1 W2", so its mapping is
W1 --> 1
W2 --> 2
W3 --> 0
You wish to take both mappings and determine the vectors [0, 1, 4] and [1, 2, 0] and then compute the angle between those vectors as a way of determining how similar or different the two documents are.
Your problem is that the dictionary does not guarantee that the key/value pairs are enumerated in any particular order.
OK, so order them.
vector1 = (from pair in map1 orderby pair.Key select pair.Value).ToArray();
vector2 = (from pair in map2 orderby pair.Key select pair.Value).ToArray();
and you're done.
Does that solve your problem, or am I misunderstanding the scenario?
If I understand correctly, you want to split a document by word frequency.
You could take the document and run a Regex over it to split out the words:
var words=Regex
.Matches(input,#"\w+")
.Cast<Match>()
.Where(m=>m.Success)
.Select(m=>m.Value);
To make the frequency map:
var map=words.GroupBy(w=>w).Select(g=>new{word=g.Key,freqency=g.Count()});
There are overloads of the GroupBy method that allow you to supply an alternative IEqualityComparer if this is important.
Reading your comments, to create a corresponding sequence of only frequencies:
map.Select(a=>a.frequency)
This sequence will be in exactly the same order as the sequence map above.
Is this any help at all?
There is also an OrderedDictionary.
Represents a collection of key/value
pairs that are accessible by the key
or index.
Something like this might work although it is definitely ugly and I believe is similar to what you were suggesting. GetWordCount() does the work.
class WordCounter
{
public Dictionary dictionary = new Dictionary();
public void CountWords(string text)
{
if (text != null && text != string.Empty)
{
text = text.ToLower();
string[] words = text.Split(' ');
if (dictionary.ContainsKey(words[0]))
{
if (text.Length > words[0].Length)
{
text = text.Substring(words[0].Length + 1);
CountWords(text);
}
}
else
{
int count = words.Count(
delegate(string s)
{
if (s == words[0]) { return true; }
else { return false; }
});
dictionary.Add(words[0], count);
if (text.Length > words[0].Length)
{
text = text.Substring(words[0].Length + 1);
CountWords(text);
}
}
}
}
public int[] GetWordCount(string text)
{
CountWords(text);
return dictionary.Values.ToArray<int>();
}
}
Would be this helpful to you:
SortedDictionary<string, int> dic = new SortedDictionary<string, int>();
for (int i = 0; i < 10; i++)
{
if (dic.ContainsKey("Word" + i))
dic["Word" + i]++;
else
dic.Add("Word" + i, 0);
}
//to get the array of words:
List<string> wordsList = new List<string>(dic.Keys);
string[] wordsArr = wordsList.ToArray();
//to get the array of values
List<int> valuesList = new List<int>(dic.Values);
int[] valuesArr = valuesList.ToArray();
If all you're trying to do is calculate cosine similarity, you don't need to convert your data to 20,000-length arrays, especially considering the data would likely be sparse with most entries being zero.
While processing the files, store the file output data into a Dictionary keyed on the word. Then to calculate the dot product and magnitudes, you iterate through the words in the full word list, look for the word in each of the file ouptut data, and use the found value if it exists and zero if it doesn't.

Categories