Dictionary<string, int> increase value - c#

I have a Dictionary<string, int> and I am reading some strings from a list... I want to add them in the dictionary, but if the string is already in the dictionary, I want its value to increase by 1.
The code I tried is as below, but there are some strings that are increased with every input.. Is something wrong?
Dictionary<string, int> dictionary = new Dictionary<string, int>();
foreach (String recordline in tags)
{
String recordstag = recordline.Split('\t')[1];
String tagToDic = recordstag.Substring(0, (recordstag.Length-1) );
if (dictionary.ContainsKey(tagToDic) == false)
{
dictionary.Add(tagToDic, 1);
}
else
{
try
{
dictionary[tagToDic] = dictionary[tagToDic] + 1;
}
catch (KeyNotFoundException ex)
{
System.Console.WriteLine("X" + tagToDic + "X");
dictionary.Add(tagToDic, 1);
}
}
}
EDIT: To answer your comments... I am removing the last char of the string because it is always a blank space...
My input is like:
10000301 business 0 0,000
10000301 management & auxiliary services 0 0,000
10000316 demographie 0 0,000
10000316 histoire de france 0 0,000
10000347 economics 0 0,000
10000347 philosophy 1 0,500
and i want only the string like "business" or "management & auxiliary services" etc.

You are splitting each string in the input string array and selecting the 2nd string in the string array. Then you are removing the last character of this 2nd string using SubString. Hence all strings that differ only in the last character would be considered the same and incremented. Thats why you might be seeing "some strings that are increased with every input".
EDIT: If the purpose of removing the last char is to remove space, Use String.Trim instead.
Another edit is using TryGetValue instead of ContainsKey which performs better to increment your value. Code has been edited below.
Try this:
Dictionary<string, int> dictionary = new Dictionary<string, int>();
foreach(string recordline in tags)
{
string recordstag = recordline.Split('\t')[1].Trim();
int value;
if (!dictionary.TryGetValue(recordstag, out value))
dictionary.Add(recordstag, 1);
else
dictionary[recordstag] = value + 1;
}

No need for a dictionary, can be solved using this Linq query.
(Assuming you want the complete string after \t)
var q =
from s in tags.Select (t => t.Substring(t.IndexOf("\t")))
group s by s into g
select new
{
g.Key,
Count = g.Count()
};
And if you need it as a dictionary just add:
var dic = q.ToDictionary (x => x.Key, x => x.Count);

Your input string first split and then substring of it returned to tagToDic, So maybe n strings have a same tagToDic.

Extension method
public static void Increment(this Dictionary<string, int> dictionary, string key)
{
int val;
dictionary.TryGetValue(key, out val);
if (val != null)
dictionary[key] = val + 1;
}
Dictionary<string, int> dictionary = new Dictionary<string, int>();
// fill with some data
dictionary.Increment("someKey");

It's probably easier just to re-add the dictionary value after you retrieve the count from the existing one.
Here's some psuedo code to handle the look up logic.
Dictionary<string, int> _dictionary = new Dictionary<string, int>();
private void AdjustWordCount(string word)
{
int count;
bool success = _dictionary.TryGetValue(word, out count);
if (success)
{
//Remove it
_dictionary.Remove(word);
//Add it back in plus 1
_dictionary.Add(word, count + 1);
}
else //could not get, add it with a count of 1
{
_dictionary.Add(word, 1);
}
}

How about:
Dictionary<string, int> dictionary = new Dictionary<string, int>();
string delimitedTags = "some tab delimited string";
List<string> tags = delimitedTags.Split(new char[] {'\t'}, StringSplitOptions.None).ToList();
foreach (string tag in tags.Distinct())
{
dictionary.Add(tag, tags.Where(t => t == tag).Count());
}

If you have them in a list you could just group them and make your list.
list.GroupBy(recordline => recordline.Split('\t').Substring(0, (recordstag.Length-1),
(key, ienum) => new {word = key, count = ienum.Count()});
Then you can put that in a dictionary or iterate it or something.

Your dictionary code looks like it will function the way you expect.
My best guess is that your string-splitting code is not working correctly.
You'd have to give us some sample inputs to verify this though.
Anyway, your entire block of code could be simplified and rewritten with LINQ as:
var dictionary = tags
.Select(t => {
var recordstag = t.Split('\t')[1];
return recordstag.Substring(0, recordstag.Length-1);
})
.GroupBy(t => t)
.ToDictionary(k => k.Key, v => v.Count())
;

Related

Reading characters from a string and counting each one of them

The issue i have with my code is as following: i cannot get my head around how to read each character and sum each up in one int for everyone at the end of all rotations. Here is my code:
class Program
{
static void Main()
{
SortedDictionary<string, int> text = new SortedDictionary<string, int>();
string[] characters = Console.ReadLine()
.Split()
.ToArray();
foreach (var character in characters)
{
if (text.ContainsKey(character))
{
text[character]++;
}
else
{
text.Add(character, 1);
}
}
foreach (var character in text)
{
Console.WriteLine($"{character.Key} -> {character.Value}");
}
}
}
I am reading here how many times a string exists in the Dictionary. What i need to get, written above, is different. Please help, thanks!
String.Split() is splitting on new lines by default so characters contains a single string with the whole line in it. If you want each of the characters, just get rid of the Split (and change the Dictionary KeyType to char to match the values):
SortedDictionary<char, int> text = new SortedDictionary<char, int>();
char[] characters = Console.ReadLine().ToArray();
// ...
https://www.ideone.com/hnMSv1
Since string implements IEnumerable<char> you actually don't even need to convert the characters into an array:
SortedDictionary<char, int> text = new SortedDictionary<char, int>();
string line = Console.ReadLine();
foreach( char character in line )
// ...
https://www.ideone.com/nLyBfC
You can use LINQ here because any string consists of char element. So, string type implements IEnumerable<char> interface:
string str = "aaabbc";
var res = str
.GroupBy(c => c)
.ToDictionary(g => new { g.Key, Count = g.Count() });
The example below demonstrates how you can get it without casting to dictionary but projecting an anonymous type and sort the number of characters in descending order:
var res2 = str
.GroupBy(c => c)
.Select(d => new { d.Key, Count = d.Count() })
.OrderByDescending(x => x.Count);

Getting a count of unique strings from a List<string[]> into a dictionary

I want to input a List<string[]> and
The output is a dictionary where the keys are unique strings used for an index and the values is an array of floats with each position in the array representing the count of the key for a string[] in the List<string[]>
So far here is what I attempted
static class CT
{
//Counts all terms in array
public static Dictionary<string, float[]> Termfreq(List<string[]> text)
{
List<string> unique = new List<string>();
foreach (string[] s in text)
{
List<string> groups = s.Distinct().ToList();
unique.AddRange(groups);
}
string[] index = unique.Distinct().ToArray();
Dictionary<string, float[]> countset = new Dictionary<string, float[]>();
return countset;
}
}
static void Main()
{
/* local variable definition */
List<string[]> doc = new List<string[]>();
string[] a = { "That", "is", "a", "cat" };
string[] b = { "That", "bat", "flew","over","the", "cat" };
doc.Add(a);
doc.Add(b);
// Console.WriteLine(doc);
Dictionary<string, float[]> ret = CT.Termfreq(doc);
foreach (KeyValuePair<string, float[]> kvp in ret)
{
Console.WriteLine("Key = {0}, Value = {1}", kvp.Key, kvp.Value);
}
Console.ReadLine();
}
I got stuck on the dictionary part. What is the most effective way to implement this?
It sounds like you could use something like:
var dictionary = doc
.SelectMany(array => array)
.Distinct()
.ToDictionary(word => word,
word => doc.Select(array => array.Count(x => x == word))
.ToArray());
In other words, first find the distinct set of words, then for each word, create a mapping.
To create a mapping, look at each array in the original document, and find the count of the occurrences of the word in that array. (So each array maps to an int.) Use LINQ to perform that mapping over the whole document, with ToArray creating an int[] for a particular word... and that's the value for that word's dictionary entry.
Note that this creates a Dictionary<string, int[]> rather than a Dictionary<string, float[]> - it seems more sensible to me, but you could always cast the result of Count to float if you really wanted to.

How to check for duplicates in an array and then do something with their values?

I have an array for example("1:2","5:90","7:12",1:70,"29:60") Wherein ID and Qty are separated by a ':' (colon), what I want to do is when there's a duplicate of IDs the program will add the qty and return the new set of arrays so in the example it will become ("1:72","5:90","7:12","29:60").
Ex.2 ("1:2","5:90","7:12","1:70","29:60","1:5") becomes ("1:77","5:90","7:12","29:60").
I want to solve it without using linq.
var foo = array.Select(s => s.Split(':'))
.GroupBy(x => x[0])
.Select(g =>
String.Format(
"{0}:{1}",
g.Key,
g.Sum(x => Int32.Parse(x[1]))
)
)
.ToArray();
Note, it's not necessary to parse the "keys," only the values.
Without LINQ:
var dictionary = new Dictionary<string, int>();
foreach (var group in array) {
var fields = group.Split(':');
if (!dictionary.ContainsKey(fields[0])) {
dictionary.Add(fields[0], 0);
}
dictionary[fields[0]] += Int32.Parse(fields[1]);
}
string[] foo = new string[dictionary.Count];
int index = 0;
foreach (var kvp in dictionary) {
foo[index++] = String.Format("{0}:{1}", kvp.Key, kvp.Value);
}
You have to do this manually. Loop through each list, check the ID for each element. Put it in a Dictionary<int, int>, Dictionary<id, qt>. If the dictionary contains the id, add it to the value.
Loop, add, check using Dictionary class.
If you want it without LINQ...
var totalQuantities = new Dictionary<int, int>();
foreach(var raw in sourceArr) {
var splitted = raw.Split(':');
int id = int.Parse(splitted[0]);
int qty = int.Parse(splitted[1]);
if(!totalQuantities.ContainsKey(id)) {
totalQuantities[id] = 0;
}
totalQuantities[id] += qty;
}
var result = new string[totalQuantities.Count];
int i=0;
foreach(var kvp in totalQuantities) {
result[i] = string.Format("{0}:{1}", kvp.Key, kvp.Value);
i++;
}
(
from raw in arr
let splitted = raw.Split(':')
let id = int.Parse(splitted[0])
let qty = int.Parse(splitted[1])
let data = new { id, qty }
group data by data.id into grp
let totalQty = grp.Sum(val => val.qty)
let newStr = string.Format("{0}:{1}", grp.Key, totalQty
select newStr
)
.ToArray()
Note that the code may contain accidental errors, as it was written in notepad.
var input=new string[]{"1:2","5:90","7:12","1:70","29:60","1:5"};
var result=input
.Select(s=>s.Split(':'))
.Select(x=>x.Select(s=>int.Parse(s)).ToArray())
.GroupBy(x=>x[0])
.Select(g=>g.Key+":"+g.Sum(x=>x[1]));
I was too lazy to specify the culture everywhere. You probably want to do that before putting it into production, or it will fail for cultures with unusual integer representations.
var totals=new Dictionary<int,int>
foreach(string s in input)
{
string[] parts=s.Split(':');
int id=int.Parse(parts[0]);
int quantity=int.Parse(parts[0]);
int totalQuantity;
if(!totals.TryGetValue(id,out totalQuantity))
totalQuantity=0;//Yes I know this is redundant
totalQuanity+=quantity;
totals[id]=totalQuantity;
}
var result=new List<string>();
foreach(var pair in totals)
{
result.Add(pair.Key+":"+pair.Value);
}
try this:
List<string> items = new List<string>(new string[] { "1:2", "5:90", "7:12", "1:70", "29:60" });
Dictionary<string, int> dictionary = new Dictionary<string, int>();
foreach (string item in items)
{
string[] data = item.Split(':');
string key = data[0];
if (!dictionary.ContainsKey(data[0]))
{
int value = dictionary[data[0]];
dictionary[key] += int.Parse(data[1]);
}
}
//Used dictionary values here

C#: Adding data to dictionary

I have a list like
List<string> TempList = new List<string> { "[66,X,X]", "[67,X,2]", "[x,x,x]" };
I need to add data to the dictionary from the above list
Dictionary<int, int> Dict = new Dictionary<int, int>();
so the Dict should contain
Key --> 66 value --> 67
i need to take 66(first value) from first string([66,X,X]) and 67(first value) from second string( [67,X,X]) and add it as a key value pair into the dictionary.
Now i'm following string replacing and looping methodology to do this .
Is there any way to do this in LINQ or Regular expression.
After your comment that you're starting from a list of lists, I understood what you were after. I'm reusing Jaroslav's 'GetNumber' function here. Wrote my sample with array of array of string, but should work just the same. The code below will throw if you have duplicate keys, which I presume is what you want if you're using a dictionary.
var input = new []
{
new [] { "[66,X,X]", "[67,X,2]", "[x,x,x]" },
new [] { "[5,X,X]", "[8,X,2]", "[x,x,x]" }
};
var query = from l in input
select new
{
Key = GetNumber(l.ElementAt(0)),
Value = GetNumber(l.ElementAt(1))
};
var dictionary = query.ToDictionary(x => x.Key, x => x.Value);
Here is an example using both string.Split() and a Regex:
namespace ConsoleApplication1
{
class Program
{
static void Main(string[] args)
{
List<string> data = new List<string>() { "[66,X,X]", "[67,X,2]", "[x,x,x]" };
addToDict(data);
Console.ReadKey();
}
private static void addToDict(List<string> items)
{
string key = items[0].Split('[', ',')[1];
string val = items[1].Split('[', ',')[1];
string pattern = #"(?:^\[)(\d+)";
Match m = Regex.Match(items[0], pattern);
key = m.Groups[1].Value;
m = Regex.Match(items[1], pattern);
val = m.Groups[1].Value;
_dict.Add(key, val);
}
static Dictionary<string, string> _dict = new Dictionary<string, string>();
}
}
i suspect that your example is quite contrived though, so there may be a better solution especially if you need to process large numbers of strings into key/value pairs (i deliberately hardcoded index values because your example was quite simple and i didn't want to over complicate the answer). If the input data is consistent in format then you can make assumptions like using fixed indexes, but if there is a possibility of some variance then there may need to be more code to check the validity of it.
You can use a regular expression to extract the value from each item in the list, and if you want, use LINQ to select out two lists and zip them together (in C# 4.0):
var regex = new Regex(#"\d+");
var allValues = TempList.Select(x =>int.Parse(regex.Match(x).Value));
var dictKeys = allValues.Where((x,index)=> index % 2 == 0); //even-numbered
var dictValues = allValues.Where((x,index)=> index % 2 > 0); //odd numbered
var dict = dictKeys.Zip(dictValues, (key,value) => new{key,value})
.ToDictionary(x=>x.key,x=>x.value);
If you're using C# 3.5, you can use Eric Lippert's implementation of Zip().
IF I understand correctly: you want to create linked nodes like 66 -> 67, 67 -> 68, ... n -> n+1?
I would not use LINQ:
private static int GetNumber(string s)
{
int endPos = s.IndexOf(',');
return Int32.Parse(s.Substring(1, endPos-1));
}
And in code:
int first, second;
for (int i = 1; i < TempList.Count; i++)
{
first = GetNumber(TempList[i - 1]);
second = GetNumber(TempList[i]);
Dict.Add(first, second);
}
You should also perform checking, etc.
The sample assumes a list with at least 2 items.
List<List<string>> source = GetSource();
Dictionary<int, int> result = source.ToDictionary(
tempList => GetNumber(tempList[0]),
tempList => GetNumber(tempList[1])
);

How to get count similar word in list?

I have C# list with lot of similar name i want to count all individual similar word.
Example
Suppose list has these values
one,one,one,two,two,four,four,four
then i want to calculate like this
one 3
two 2
four 3
how can i calculate value like this from list.
I would split the string on comma, loop through all the results and add each word to a hashtable or dictionary with a value of one. If the word (key) is already present, then increment the value.
string[] values = "one,one,one,two,two,four,four,four".Split(',');
var counts = new Dictionary<string, int>();
foreach (string value in values) {
if (counts.ContainsKey(value))
counts[value] = counts[value] + 1;
else
counts.Add(value, 1);
}
Or, if you prefer, here is a LINQ solution
var counts = values.GroupBy<string, string, int>(k => k, e => 1)
.Select(f => new KeyValuePair<string, int>(f.Key, f.Sum()))
.ToDictionary(k => k.Key, e => e.Value);
Here is a solution based on Linq:
string s = "one,one,one,two,two,four,four,four";
List<string> list = s.Split(',').ToList();
Dictionary<string, int> dictionary = list.GroupBy(x => x)
.ToDictionary(x => x.Key, x => x.Count());
foreach (var kvp in dictionary)
Console.WriteLine("{0}: {1}", kvp.Key, kvp.Value);
Output:
one: 3
two: 2
four: 3
This solutions doesn't take advantage of the fact that the common values are consecutive. If this is always the case, a slightly faster solution could be written, but this is fine for short lists, or if the items can come in any order.
Dictionaty<string, int> listCount = new Dictionaty<string, int>();
for (int i = 0; i < yourList.Count; i++)
{
if(listCount.ContainsKey(yourList[i]))
listCount[yourList[i].Trim()] = listCount[yourList[i].Trim()] + 1;
else
listCount[yourList[i].Trim()] = 1;
}
For List, you could do the following (untested):
List<string> list = new List<string>()
{
"One",
"One",
"Two",
// etc
}
Dictionary<string, int> d = new Dictionary<string, int>();
foreach (string s in list)
{
if (d.ContainsKey(s))
d.Add(s, 1);
else
d[s]++;
}
The preferred (and cleaner) method is to do this using GroupBy and Count with Linq, but I don't have the type to type out the syntax at the moment.
Good luck!

Categories

Resources