picking the highest value from a dictionary using its key - c#

So the aim is to sort a word into letters and give it a score based on each letters worth. i have this working and have put it int a Dictionary using the score as the key and word as the value.
I need to find the highest scoring word that uses only the letters provided (each only used once), and if there are multiple with the same score then the first that was added to the dictionary needs to be printed. the code is as below;
Dictionary<string, int> wordHolder = new Dictionary<string, int>();
int N = int.Parse(Console.ReadLine());
for (int i = 0; i < N; i++)
{
string W = Console.ReadLine();
char[] splitWord = W.ToCharArray();
Console.Error.WriteLine(W);
int points = splitWord.Sum(c => letterPoints.First(kvp => kvp.Value.Contains(c)).Key);
wordHolder.Add(W, points);
Console.Error.WriteLine(points);
}
string LETTERS = Console.ReadLine();
Console.Error.WriteLine(LETTERS);
Letters is the provided characters given in a single string

You can order by descending and get first element:
wordHolder.OrderByDescending(x => x.Value).First();
Or Order by ascending and get last element:
wordHolder.OrderBy(x => x.Value).Last();

using System;
using System.Collections.Generic;
using System.Linq;
namespace ConsoleApplication9
{
internal static class Program
{
private static void Main()
{
// --- building up the data so the next (repeated) steps are efficient: ---
// your words and points
var wordHolder = new Dictionary<string, int>();
// INSERT DATA INTO wordHolder HERE
// create a dictionary where you can access all words and their points
// efficiently by the letters you have available:
var efficientAccessByLetters = wordHolder.Select(entry =>
new
{
Index = new string(entry.Key.OrderBy(c => c).ToArray()),
Word = entry.Key,
Points = entry.Value
})
.GroupBy(x => x.Index)
.ToDictionary(x => x.Key,
x => x.OrderByDescending(p => p.Points).ToList());
// --- Repeat this steps as many times as you like: ---
while (true)
{
Console.WriteLine("Enter letters available:");
// get letters that you want to build he best word from:
var availableLetters = Console.ReadLine();
// normalize the letters for fast index search by sorting them
var normalized = new string(availableLetters.OrderBy(c => c).ToArray());
if (!efficientAccessByLetters.ContainsKey(normalized))
{
Console.WriteLine("Sorry, no matching words found.");
}
else
{
// find all words and their respective points by index access
var wordsThatMatchLetters = efficientAccessByLetters[normalized];
// as words are sorted by points, just get the first
var best = wordsThatMatchLetters.First();
// output
Console.WriteLine("Best Match: {0} for {1} points", best.Word, best.Points);
}
}
}
}
}

The best of way of doing it without a dictionary.
public static string High(string s)
{
return s.Split(' ').OrderByDescending(a => a.Select(b => b - 96).Sum()).Last();
}

Related

C# looping through a list to find character counts

I'm trying to loop through a string to find the character, ASCII value, and the number of times the character occurs. So far, I have found each unique character and ASCII value using foreach statements, and finding if the value was already in the list, then don't add it, otherwise add it. However I'm struggling with the count portion. I was thinking the logic would be "if I am already in the list, don't count me again, however, increment my frequency"
I've tried a few different things, such as trying to find the index of the character it found and adding to that specific index, but i'm lost.
string String = "hello my name is lauren";
char[] String1 = String.ToCharArray();
// int [] frequency = new int[String1.Length]; //array of frequency counter
int length = 0;
List<char> letters = new List<char>();
List<int> ascii = new List<int>();
List<int> frequency = new List<int>();
foreach (int ASCII in String1)
{
bool exists = ascii.Contains(ASCII);
if (exists)
{
//add to frequency at same index
//ascii.Insert(1, ascii);
//get { ASCII[index]; }
}
else
{
ascii.Add(ASCII);
//add to frequency at new index
}
}
foreach (char letter in String1)
{
bool exists = letters.Contains(letter);
if (exists)
{
//add to frequency at same index
}
else
{
letters.Add(letter);
//add to frequency at new index
}
}
length = letters.Count;
for (int j = 0; j<length; ++j)
{
Console.WriteLine($"{letters[j].ToString(),3} {"(" + ascii[j] + ")"}\t");
}
Console.ReadLine();
}
}
}
I'm not sure if I understand your question but that what you are looking for may be Dictionary<T,T> instead of List<T>. Here are examples of solutions to problems i think you trying to solve.
Counting frequency of characters appearance
Dictionary<int, int> frequency = new Dictionary<int, int>();
foreach (int j in String)
{
if (frequency.ContainsKey(j))
{
frequency[j] += 1;
}
else
{
frequency.Add(j, 1);
}
}
Method to link characters to their ASCII
Dictionary<char, int> ASCIIofCharacters = new Dictionary<char, int>();
foreach (char i in String)
{
if (ASCIIofCharacters.ContainsKey(i))
{
}
else
{
ASCIIofCharacters.Add(i, (int)i);
}
}
A simple LINQ approach is to do this:
string String = "hello my name is lauren";
var results =
String
.GroupBy(x => x)
.Select(x => new { character = x.Key, ascii = (int)x.Key, frequency = x.Count() })
.ToArray();
That gives me:
If I understood your question, you want to map each char in the provided string to the count of times it appears in the string, right?
If that is the case, there are tons of ways to do that, and you also need to choose in which data structure you want to store the result.
Assuming you want to use linq and store the result in a Dictionary<char, int>, you could do something like this:
static IDictionary<char, int> getAsciiAndFrequencies(string str) {
return (
from c in str
group c by Convert.ToChar(c)
).ToDictionary(c => c.Key, c => c.Count());
}
And use if like this:
var f = getAsciiAndFrequencies("hello my name is lauren");
// result: { h: 1, e: 3, l: 3, o: 1, ... }
You are creating a histogram. But you should not use List.Contains as it gets ineffective as the list grows. You have to go through the list one item after another. Better use Dictionary which is based on hashing and you go directly to the item. The code may look like this
string str = "hello my name is lauren";
var dict = new Dictionary<char, int>();
foreach (char c in str)
{
dict.TryGetValue(c, out int count);
dict[c] = ++count;
}
foreach (var pair in dict.OrderBy(r => r.Key))
{
Console.WriteLine(pair.Value + "x " + pair.Key + " (" + (int)pair.Key + ")");
}
which gives
4x (32)
2x a (97)
3x e (101)
1x h (104)
1x i (105)
3x l (108)
2x m (109)
2x n (110)
1x o (111)
1x r (114)
1x s (115)
1x u (117)
1x y (121)

Sort a List in which each element contains 2 Values

I have a text file that contains Values in this Format: Time|ID:
180|1
60 |2
120|3
Now I want to sort them by Time. The Output also should be:
60 |2
120|3
180|1
How can I solve this problem? With this:
var path = #"C:\Users\admin\Desktop\test.txt";
List<string> list = File.ReadAllLines(path).ToList();
list.Sort();
for (var i = 0; i < list.Count; i++)
{
Console.WriteLine(list[i]);
}
I got no success ...
3 steps are necessary to do the job:
1) split by the separator
2) convert to int because in a string comparison a 6 comes after a 1 or 10
3) use OrderBy to sort your collection
Here is a linq solution in one line doing all 3 steps:
list = list.OrderBy(x => Convert.ToInt32(x.Split('|')[0])).ToList();
Explanation
x => lambda expression, x denotes a single element in your list
x.Split('|')[0] splits each string and takes only the first part of it (time)
Convert.ToInt32(.. converts the time into a number so that the ordering will be done in the way you desire
list.OrderBy( sorts your collection
EDIT:
Just to understand why you got the result in the first place here is an example of comparison of numbers in string representation using the CompareTo method:
int res = "6".CompareTo("10");
res will have the value of 1 (meaning that 6 is larger than 10 or 6 follows 10)
According to the documentation->remarks:
The CompareTo method was designed primarily for use in sorting or alphabetizing operations.
You should parse each line of the file content and get values as numbers.
string[] lines = File.ReadAllLines("path");
// ID, time
var dict = new Dictionary<int, int>();
// Processing each line of the file content
foreach (var line in lines)
{
string[] splitted = line.Split('|');
int time = Convert.ToInt32(splitted[0]);
int ID = Convert.ToInt32(splitted[1]);
// Key = ID, Value = Time
dict.Add(ID, time);
}
var orderedListByID = dict.OrderBy(x => x.Key).ToList();
var orderedListByTime = dict.OrderBy(x => x.Value).ToList();
Note that I use your ID reference as Key of dictionary assuming that ID should be unique.
Short code version
// Key = ID Value = Time
var orderedListByID = lines.Select(x => x.Split('|')).ToDictionary(x => Convert.ToInt32(x[1]), x => Convert.ToInt32(x[0])).OrderBy(x => x.Key).ToList();
var orderedListByTime = lines.Select(x => x.Split('|')).ToDictionary(x => Convert.ToInt32(x[1]), x => Convert.ToInt32(x[0])).OrderBy(x => x.Value).ToList();
You need to convert them to numbers first. Sorting by string won't give you meaningful results.
times = list.Select(l => l.Split('|')[0]).Select(Int32.Parse);
ids = list.Select(l => l.Split('|')[1]).Select(Int32.Parse);
pairs = times.Zip(ids, (t, id) => new{Time = t, Id = id})
.OrderBy(x => x.Time)
.ToList();
Thank you all, this is my Solution:
var path = #"C:\Users\admin\Desktop\test.txt";
List<string> list = File.ReadAllLines(path).ToList();
list = list.OrderBy(x => Convert.ToInt32(x.Split('|')[0])).ToList();
for(var i = 0; i < list.Count; i++)
{
Console.WriteLine(list[i]);
}
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
public class TestClass {
public static void main(String[] args) {
List <LineItem> myList = new ArrayList<LineItem>();
myList.add(LineItem.getLineItem(500, 30));
myList.add(LineItem.getLineItem(300, 20));
myList.add(LineItem.getLineItem(900, 100));
System.out.println(myList);
Collections.sort(myList);
System.out.println("list after sort");
System.out.println(myList);
}
}
class LineItem implements Comparable<LineItem>{
int time;
int id ;
#Override
public String toString() {
return ""+ time + "|"+ id + " ";
}
#Override
public int compareTo(LineItem o) {
return this.time-o.time;
}
public static LineItem getLineItem( int time, int id ){
LineItem l = new LineItem();
l.time=time;
l.id=id;
return l;
}
}

How to sort a dictionary in C# .net

I need to make a frequency analysis console program using c#. It has to show the 10 most frequent letters from a textfile. I have managed to display the first 10 letters read by the program and the frequency of each character. I, however, don't know how to sort the dictionary. This is the code I have so far.
I must also give the user the option to the frequency analysis in case sensitive mode (as it is right now) and case insensitive. Help with this issue will also be appreciated. Thank You!
static void Main(string[] args)
{
// 1.
// Array to store frequencies.
int[] c = new int[(int)char.MaxValue];
// 2.
// Read entire text file.
// string root = Server.MapPath("~");
// string FileName = root + "/App_Data/text.txt";
//string s = File.ReadAllText(FileName);
foreach (string line in File.ReadLines(#"c:\Users\user\Documents\Visual Studio 2015\Projects\ConsoleApplication1\ConsoleApplication1\App_Data\text.txt", Encoding.UTF8)) {
var fileStream = new FileStream(#"c:\Users\user\Documents\Visual Studio 2015\Projects\ConsoleApplication1\ConsoleApplication1\App_Data\text.txt", FileMode.Open, FileAccess.Read);
using (var streamReader = new StreamReader(fileStream, Encoding.UTF8))
{
string line2;
while ((line2 = streamReader.ReadLine()) != null)
{
// process the line
// 3.
// Iterate over each character.
foreach (char t in line)
{
// Increment table.
c[(int)t]++;
}
// 4.
// Write all letters found.
int counter = 0;
for (int i = 0; i < (int)char.MaxValue; i++)
{
if (c[i] > 0 && counter < 11 &&
char.IsLetterOrDigit((char)i))
{
++counter;
Console.WriteLine("Letter: {0} Frequency: {1}",
(char)i,
c[i]);
}
}
}
}
Console.ReadLine();
}
}
If all you want to do is to found frequencies, you don't want any dictionaries, but a Linq. Such tasks are ones Linq has been designed for:
...
using System.Linq;
...
static void Main(string[] args) {
var result = File
.ReadLines(#"...", Encoding.UTF8)
.SelectMany(line => line) // string into characters
.Where(c => char.IsLetterOrDigit(c))
.GroupBy(c => c)
.Select(chunk => new {
Letter = chunk.Key,
Count = chunk.Count() })
.OrderByDescending(item => item.Count)
.ThenBy(item => item.Letter) // in case of tie sort by letter
.Take(10)
.Select(item => $"{item.Letter} freq. {item.Count}"); // $"..." - C# 6.0 syntax
Console.Write(string.Join(Environment.NewLine, result));
}
I like #Dmitry Bychenko's answer because it's very terse. But, if you have a very large file then that solution may not be optimal for you. The reason being, that solution has to read the entire file into memory to process it. So, in my tests, I got up to around 1GB of memory usage for a 500MB file. The solution below, while not quite as terse, uses constant memory (basically 0) and runs as fast or faster than the Linq version in my tests.
Dictionary<char, int> freq = new Dictionary<char, int>();
using (StreamReader sr = new StreamReader(#"yourBigFile")) {
string line;
while ((line = sr.ReadLine()) != null) {
foreach (char c in line) {
if (!freq.ContainsKey(c)) {
freq[c] = 0;
}
freq[c]++;
}
}
}
var result = freq.Where(c => char.IsLetterOrDigit(c.Key)).OrderByDescending(x => x.Value).Take(10);
Console.WriteLine(string.Join(Environment.NewLine, result));
It would be easier to use the actual Dictionary type in C# here, rather than an array:
Dictionary<char, int> characterCountDictionary = new Dictionary<char, int>();
You add a key if it doesn't exist already (and insert a value of 1), or you increment the value if it does exist. Then you can pull out the keys of your dictionary as a list and sort them, iterating to find the values. If you do case insensitive you'd just convert all upper case to lower case before inserting into the dictionary.
Here's the MSDN page for the examples for Dictionary: https://msdn.microsoft.com/en-us/library/xfhwa508(v=vs.110).aspx#Examples

finding max value in a c# array

I am making a program in c# that will take in a list of names and scores from a text document, get the score on its own and then find the highest of the scores. I can separate the name from the score when it is just one but as soon as I try make it an array I do not have any idea what I am doing.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
class Program
{
static void Main(string[] args)
{
System.IO.File.Exists(#"U:\StudentExamMarks.txt");
string[] text = System.IO.File.ReadAllLines(#"U:\StudentExamMarks.txt");
int a = 0;
string[] results = new string[a];
for(int i=0;i<text.Length ; i++ )
{
int x = text[i].LastIndexOf("\t");
int y = text[i].Length;
int z = (y - (x + 1));
results[a] = text[i].Substring((x+1), (z));
a++;
Console.WriteLine("{0}", results);
}
}
}
This is what I have so far
the list is as follows
John Cross 100
Christina Chandler 105
Greg Hamilton 107
Pearl Becker 111
Angel Ford 115
Wendell Sparks 118
like I said when I attempted it without an array I can get it to display the 100 from the first result. I also do not know how when I find the largest result how to link it back to the students name.
I suggest to use a class to hold all properties, that improves readability a lot:
public class StudentExam
{
public string StudentName { get; set; }
public int Mark { get; set; }
}
and following to read all lines and to fill a List<StudentExam>:
var lines = File.ReadLines(#"U:\StudentExamMarks.txt")
.Where(l => !String.IsNullOrWhiteSpace(l));
List<StudentExam> studentsMarks = new List<StudentExam>();
foreach (string line in lines)
{
string[] tokens = line.Split('\t');
string markToken = tokens.Last().Trim();
int mark;
if (tokens.Length > 1 && int.TryParse(markToken, out mark))
{
StudentExam exam = new StudentExam{
Mark = mark,
StudentName = String.Join(" ", tokens.Take(tokens.Length - 1)).Trim()
};
studentsMarks.Add(exam);
}
}
Now it's easy to get the max-mark:
int maxMark = studentsMarks.Max(sm => sm.Mark); // 118
To find the highest score, you can use Linq with Regex like this
var lines = new[] {
"John Cross 100",
"Christina Chandler 105",
"Greg Hamilton 107",
"Pearl Becker 111"
};
var maxScore = lines.Max(l => int.Parse(Regex.Match(l, #"\b\d+\b").Value));
Here, I'm assuming you have read the file correctly into lines and all of them has a valid int value of the score.
If the end of each entry is always a space followed by the student's score, you can use a simple substring:
int max = text.Max(x => Convert.ToInt32(x.Substring(x.LastIndexOf(' '))));
For each entry, create a substring that starts at the last index of ' ' and then convert that to an integer. Then return the max of those values.

Separate words from a string in C#

So i'm working on a program for a university degree. First requirement was to show the number of times each letter of the alphabet appears in a string. Now to develop this program further i would like to show all the words that are in the string, in a list. Here is the current code that i have.
public void occurances()
{
string sentence;
Console.WriteLine("\n");
Console.WriteLine("Please enter a random sentence and press enter");
Console.WriteLine("\n");
var occurances = new Dictionary<char, int>();
var words = occurances;
//a for each loop, and within it, the char variable is a assigned named "characters"
//The value "characters" will represent all the characters in the sentence string.
sentence = Console.ReadLine();
foreach (char characters in sentence)
{
//if the sentence contains characters
if (occurances.ContainsKey(characters))
//add 1 to the value of occurances
occurances[characters] = occurances[characters] + 1;
//otherwise keep the occurnaces value as 1
else
occurances[characters] = 1;
}
foreach (var entry in occurances)
{
//write onto the screen in position 0 and 1, where 0 will contain the entry key
// and 1 will contain the amount of times the entry has been entered
Console.WriteLine("{0}: {1}", entry.Key, entry.Value);
}
//Pause
Console.ReadLine();
}
For 1st Requirement:
var charGroups = sentence.GroupBy(x => x).OrderByDescending(x => x.Count());
For 2nd Requirement:
How to: Count Occurrences of a Word in a String (LINQ)
I thinks the easiest way would be this:
var WordList = YourString.Split(' ').toList(); // Making the list of words
var CharArray = YourString.toCharArray(); // Counting letters
var q = from x in CharArray
group x by x into g
let count = g.Count()
orderby count descending
select new {Value = g.Key, Count = count};

Categories