How to split string and convert to int - c#

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.

Related

How to set string values into an enumerator

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
}

LINQ non-linear order by string length

I'm trying to get a list of string ordered such that the longest are on either end of the list and the shortest are in the middle. For example:
A
BB
CCC
DDDD
EEEEE
FFFFFF
would get sorted as:
FFFFFF
DDDD
BB
A
CCC
EEEEE
EDIT: To clarify, I was specifically looking for a LINQ implementation to achieve the desired results because I wasn't sure how/if it was possible to do using LINQ.
You could create two ordered groups, then order the first group descending(already done) and the second group ascending:
var strings = new List<string> {
"A",
"BB",
"CCC",
"DDDD",
"EEEEE",
"FFFFFF"};
var two = strings.OrderByDescending(str => str.Length)
.Select((str, index) => new { str, index })
.GroupBy(x => x.index % 2)
.ToList(); // two groups, ToList to prevent double execution in following query
List<string> ordered = two.First()
.Concat(two.Last().OrderBy(x => x.str.Length))
.Select(x => x.str)
.ToList();
Result:
[0] "FFFFFF" string
[1] "DDDD" string
[2] "BB" string
[3] "A" string
[4] "CCC" string
[5] "EEEEE" string
Don't ask how and why... ^^
list.Sort(); // In case the list is not already sorted.
var length = list.Count;
var result = Enumerable.Range(0, length)
.Select(i => length - 1 - 2 * i)
.Select(i => list[Math.Abs(i - (i >> 31))])
.ToList();
Okay, before I forget how it works, here you go.
A list with 6 items for example has to be reordered to this; the longest string is at index 5, the shortest one at index 0 of the presorted list.
5 3 1 0 2 4
We start with Enumerable.Range(0, length) yielding
0 1 2 3 4 5
then we apply i => length - 1 - 2 * i yielding
5 3 1 -1 -3 -5
and we have the non-negative part correct. Now note that i >> 31 is an arithmetic left shift and will copy the sign bit into all bits. Therefore non-negative numbers yield 0 while negative numbers yield -1. That in turn means subtracting i >> 31 will not change non-negative numbers but add 1 to negative numbers yielding
5 3 1 0 -2 -4
and now we finally apply Math.Abs() and get
5 3 1 0 2 4
which is the desired result. It works similarly for lists of odd length.
Just another option, which I find more readable and easy to follow:
You have an ordered list:
var strings = new List<string> {
"A",
"BB",
"CCC",
"DDDD",
"EEEEE",
"FFFFFF"};
Create a new list and simply alternate where you add items::
var new_list = new List<string>(); // This will hold your results
bool start = true; // Insert at head or tail
foreach (var s in strings)
{
if (start)
new_list.Insert(0,s);
else
new_list.Add(s);
start = !start; // Flip the insert location
}
Sweet and simple :)
As for Daniel Bruckner comment, if you care about which strings comes first, you could also change the start condition to:
// This will make sure the longest strings is first
bool start= strings.Count()%2 == 1;

A concise way to generate an array of integers 1 to 100 in c#

I am looking for a concise way to generate an array of integers 1 to 100 in c# , ie
int[] values = {1,2,3 ..., 100};
so that I can use the array in a foreach loop:
foreach (var i in values)
{
// do whatever
}
Any ideas?
Using Enumerable.Range:
Enumerable.Range(1, 100).ToArray();
There's probably not much point in me putting this - Oded's 18 votes (including my own +1) pretty much say it all, but just to point out that if you're then going to use the integers in the array, to produce something - let's say an object - then you can roll the whole thing up.
So, let's say you want some strings:
var strings = Enumerable.Range(1,100)
.Select(i => i.ToString()).ToArray();
Gives you an array of strings.
Or perhaps a MyWidget that's produced from a method call, which uses the index for something:
var myWidgets = Enumerable.Range(1,100)
.Select(i => ProduceMyWidget(i)).ToArray();
If the original foreach code block was more than one line of code - then you just use a {} block
var myWidgets = Enumerable.Range(1,100)
.Select(i => {
if(i == 57)
return ProduceSpecial57Widget(i);
else
ProduceByWidget(i);
}).ToArray();
Obviously this last example is a bit silly - but it illustrates often how a traditional foreach can be replaced with a Select plus ToArray() call.

Help Needed to convert a C# List into a proper format

I'm a bit new to C# and need help with the following problem
I have a List ticker which contains following values in it
ticker[0] =1
ticker[1] = 122
ticker[2] = 321
.....
ticker[n] = n // where n is some random number
Now the problem is that I need to create an object List which looks like
keys:[[1,66],[122,66],[321,66],.....,[n,66]]
Any help or suggestion is greatly appreciated.
Thanks in Advance
--P
Easy:
var pairs = ticker.Select(x=>new[]{x,66}).ToList();
pairs will be an list of 2-element integer arrays, where each element in your original array is paired with a second value of 66.
You could also use the same statement to create a Tuple (in .NET 4.0) of two integers:
var pairs = ticker.Select(x=>new Tuple<int,int>(x,66)).ToList();
This is a little more O/O; you access the first and second values of the pair using .Value1 and .Value2 instead of [0] and [1].
If you want to create an array of arrays:
int[][] keys = ticker.Select(n => new int[] { n, 66} ).ToArray();
If you want to create a string:
string s = "keys:[" + String.Join(",", ticker.Select(n => "[" + n.ToString() + ",66]")) + "]";
Using Linq, if you want to map the value to the index.
ticker.Select((val, index) => new[] { val, index }).ToList();
If you literally want the number 66 after each item:
ticker.Select(val => new[] { val, 66 }).ToList();
That will create a list of arrays, each the pair of values you wanted.

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