Finding longest word in string - c#

Ok, so I know that questions LIKE this have been asked a lot on here, but I can't seem to make solutions work.
I am trying to take a string from a file and find the longest word in that string.
Simples.
I think the issue is down to whether I am calling my methods on a string[] or char[], currently stringOfWords returns a char[].
I am trying to then order by descending length and get the first value but am getting an ArgumentNullException on the OrderByDescending method.
Any input much appreciated.
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Runtime.CompilerServices;
using System.Text;
using System.Threading.Tasks;
namespace TextExercises
{
class Program
{
static void Main(string[] args)
{
var fileText = File.ReadAllText(#"C:\Users\RichardsPC\Documents\TestText.txt");
var stringOfWords = fileText.ToArray();
Console.WriteLine("Text in file: " + fileText);
Console.WriteLine("Words in text: " + fileText.Split(' ').Length);
// This is where I am trying to solve the problem
var finalValue = stringOfWords.OrderByDescending(n => n.length).First();
Console.WriteLine("Largest word is: " + finalValue);
}
}
}

Don't split the string, use a Regex
If you care about performance you don't want to split the string. The reason in order to do the split method will have to traverse the entire string, create new strings for the items it finds to split and put them into an array, computational cost of more than N, then doing an order by you do another (at least) O(nLog(n)) steps.
You can use a Regex for this, which will be more efficient, because it will only iterate over the string once
var regex = new Regex(#"(\w+)\s",RegexOptions.Compiled);
var match = regex.Match(fileText);
var currentLargestString = "";
while(match.Success)
{
if(match.Groups[1].Value.Length>currentLargestString.Length)
{
currentLargestString = match.Groups[1].Value;
}
match = match.NextMatch();
}
The nice thing about this is that you don't need to break the string up all at once to do the analysis and if you need to load the file incrementally is a fairly easy change to just persist the word in an object and call it against multiple strings
If you're set on using an Array don't order by just iterate over
You don't need to do an order by your just looking for the largest item, computational complexity of order by is in most cases O(nLog(n)), iterating over the list has a complexity of O(n)
var largest = "";
foreach(var item in strArr)
{
if(item.Length>largest.Length)
largest = item;
}

Method ToArray() in this case returns char[] which is an array of individual characters. But instead you need an array of individual words. You can get it like this:
string[] stringOfWords = fileText.Split(' ');
And you have a typo in your lambda expression (uppercase L):
n => n.Length

Try this:
var fileText = File.ReadAllText(#"C:\Users\RichardsPC\Documents\TestText.txt");
var words = fileText.Split(' ')
var finalValue = fileText.OrderByDescending(n=> n.Length).First();
Console.WriteLine("Longest word: " + finalValue");

As suggested in the other answer, you need to split your string.
string[] stringOfWords = fileText.split(new Char [] {',' , ' ' });
//all is well, now let's loop over it and see which is the biggest
int biggest = 0;
int biggestIndex = 0;
for(int i=0; i<stringOfWords.length; i++) {
if(biggest < stringOfWords[i].length) {
biggest = stringOfWords[i].length;
biggestIndex = i;
}
}
return stringOfWords[i];
What we're doing here is splitting the string based on whitespace (' '), or commas- you can add an unlimited number of delimiters there - each word, then, gets its own space in the array.
From there, we're iterating over the array. If we encounter a word that's longer than the current longest word, we update it.

Related

Optimize an iteration of IEnumerable<string> [duplicate]

for long time , I always append a string in the following way.
for example if i want to get all the employee names separated by some symbol , in the below example i opeted for pipe symbol.
string final=string.Empty;
foreach(Employee emp in EmployeeList)
{
final+=emp.Name+"|"; // if i want to separate them by pipe symbol
}
at the end i do a substring and remove the last pipe symbol as it is not required
final=final.Substring(0,final.length-1);
Is there any effective way of doing this.
I don't want to appened the pipe symbol for the last item and do a substring again.
Use string.Join() and a Linq projection with Select() instead:
finalString = string.Join("|", EmployeeList.Select( x=> x.Name));
Three reasons why this approach is better:
It is much more concise and readable
– it expresses intend, not how you
want to achieve your goal (in your
case concatenating strings in a
loop). Using a simple projection with Linq also helps here.
It is optimized by the framework for
performance: In most cases string.Join() will
use a StringBuilder internally, so
you are not creating multiple strings that are
then un-referenced and must be
garbage collected. Also see: Do not
concatenate strings inside loops
You don’t have to worry about special cases. string.Join()
automatically handles the case of
the “last item” after which you do
not want another separator, again
this simplifies your code and makes
it less error prone.
I like using the aggregate function in linq, such as:
string[] words = { "one", "two", "three" };
var res = words.Aggregate((current, next) => current + ", " + next);
You should join your strings.
Example (borrowed from MSDN):
using System;
class Sample {
public static void Main() {
String[] val = {"apple", "orange", "grape", "pear"};
String sep = ", ";
String result;
Console.WriteLine("sep = '{0}'", sep);
Console.WriteLine("val[] = {{'{0}' '{1}' '{2}' '{3}'}}", val[0], val[1], val[2], val[3]);
result = String.Join(sep, val, 1, 2);
Console.WriteLine("String.Join(sep, val, 1, 2) = '{0}'", result);
}
}
For building up like this, a StringBuilder is probably a better choice.
For your final pipe issue, simply leave the last append outside of the loop
int size = EmployeeList.length()
for(int i = 0; i < size - 1; i++)
{
final+=EmployeeList.getEmployee(i).Name+"|";
}
final+=EmployeeList.getEmployee(size-1).Name;

Get values from a comma separated string containing less than a value

I am attempting to compare a comma separated string against a decimal variable and find only the amounts less than my variable.
The problem I'm having is my string looks like so:
1usd,5usd,10usd,20usd
I was able to separate the string into a collection by using the comma separator and regex split, but I don't think this is the best approach since I need to check just the value and reconstruct with the us and comma seperation.
A real world example my program will be handling is
decimal changeAvil = 10
notesSet = 1usd,5usd,10usd,20usd
Result should be notesSet = 1usd,5usd
Its not the prettiest code that has ever been written, but is does the job.
I use Linq to select the prefixes of the strings that are numbers, and then compare these to the value of changeAvil.
using System;
using System.Linq;
namespace stack
{
class Program
{
static void Main(string[] args)
{
decimal changeAvil = 10;
var noteSet = "1usd,5usd,10usd,20usd";
var notes = noteSet.Split(',');
var dict =
notes.ToDictionary(
x => int.Parse(new string(x.TakeWhile(c => char.IsNumber(c))
.ToArray())), // key
x => x); // value
var selection = dict.Where(kvp => kvp.Key <= changeAvil)
.Select(kvp => kvp.Value)
.ToList();
foreach (var s in selection) {
Console.WriteLine(s);
}
}
}
}
The solution returns 1usd, 5usd, and 10usd. If your do not want 10usd to be part of the result change kvp.Key <= changeAvil to kvp.Key < changeAvil in the Where clause of the Linq expression.
You can use split command and remove the letters 'usd' and then iterate through the array and compare
decimal changeAvil = 10
notesSet = 1usd,5usd,10usd,20usd
string noteset_new = noteset.Replace('usd',''); //remove usd
string[] noteset_array = noteset_new.split[',']; //split in to array
now you can iterate the above noteset_array and do what every you want to do.
Using replace and split on the string is using two iterations through the strings characters.
A better way to get the array will be to first add a comma to the end of the string and then use split:
notesSet = 1usd,5usd,10usd,20usd
string[] noteset_array = (notesSet + ',').split['usd,']; //split in to array

grouping adjacent similar substrings

I am writing a program in which I want to group the adjacent substrings, e.g ABCABCBC can be compressed as 2ABC1BC or 1ABCA2BC.
Among all the possible options I want to find the resultant string with the minimum length.
Here is code what i have written so far but not doing job. Kindly help me in this regard.
using System;
using System.Collections.Generic;
using System.Linq;
namespace EightPrgram
{
class Program
{
static void Main(string[] args)
{
string input;
Console.WriteLine("Please enter the set of operations: ");
input = Console.ReadLine();
char[] array = input.ToCharArray();
List<string> list = new List<string>();
string temp = "";
string firstTemp = "";
foreach (var x in array)
{
if (temp.Contains(x))
{
firstTemp = temp;
if (list.Contains(firstTemp))
{
list.Add(firstTemp);
}
temp = "";
list.Add(firstTemp);
}
else
{
temp += x;
}
}
/*foreach (var item in list)
{
Console.WriteLine(item);
}*/
Console.ReadLine();
}
}
}
You can do this with recursion. I cannot give you a C# solution, since I do not have a C# compiler here, but the general idea together with a python solution should do the trick, too.
So you have an input string ABCABCBC. And you want to transform this into an advanced variant of run length encoding (let's called it advanced RLE).
My idea consists of a general first idea onto which I then apply recursion:
The overall target is to find the shortest representation of the string using advanced RLE, let's create a function shortest_repr(string).
You can divide the string into a prefix and a suffix and then check if the prefix can be found at the beginning of the suffix. For your input example this would be:
(A, BCABCBC)
(AB, CABCBC)
(ABC, ABCBC)
(ABCA, BCBC)
...
This input can be put into a function shorten_prefix, which checks how often the suffix starts with the prefix (e.g. for the prefix ABC and the suffix ABCBC, the prefix is only one time at the beginning of the suffix, making a total of 2 ABC following each other. So, we can compact this prefix / suffix combination to the output (2ABC, BC).
This function shorten_prefix will be used on each of the above tuples in a loop.
After using the function shorten_prefix one time, there still is a suffix for most of the string combinations. E.g. in the output (2ABC, BC), there still is the string BC as suffix. So, need to find the shortest representation for this remaining suffix. Wooo, we still have a function for this called shortest_repr, so let's just call this onto the remaining suffix.
This image displays how this recursion works (I only expanded one of the node after the 3rd level, but in fact all of the orange circles would go through recursion):
We start at the top with a call of shortest_repr to the string ABABB (I selected a shorter sample for the image). Then, we split this string at all possible split positions and get a list of prefix / suffix pairs in the second row. On each of the elements of this list we first call the prefix/suffix optimization (shorten_prefix) and retrieve a shortened prefix/suffix combination, which already has the run-length numbers in the prefix (third row). Now, on each of the suffix, we call our recursion function shortest_repr.
I did not display the upward-direction of the recursion. When a suffix is the empty string, we pass an empty string into shortest_repr. Of course, the shortest representation of the empty string is the empty string, so we can return the empty string immediately.
When the result of the call to shortest_repr was received inside our loop, we just select the shortest string inside the loop and return this.
This is some quickly hacked code that does the trick:
def shorten_beginning(beginning, ending):
count = 1
while ending.startswith(beginning):
count += 1
ending = ending[len(beginning):]
return str(count) + beginning, ending
def find_shortest_repr(string):
possible_variants = []
if not string:
return ''
for i in range(1, len(string) + 1):
beginning = string[:i]
ending = string[i:]
shortened, new_ending = shorten_beginning(beginning, ending)
shortest_ending = find_shortest_repr(new_ending)
possible_variants.append(shortened + shortest_ending)
return min([(len(x), x) for x in possible_variants])[1]
print(find_shortest_repr('ABCABCBC'))
print(find_shortest_repr('ABCABCABCABCBC'))
print(find_shortest_repr('ABCABCBCBCBCBCBC'))
Open issues
I think this approach has the same problem as the recursive levenshtein distance calculation. It calculates the same suffices multiple times. So, it would be a nice exercise to try to implement this with dynamic programming.
If this is not a school assignment or performance critical part of the code, RegEx might be enough:
string input = "ABCABCBC";
var re = new Regex(#"(.+)\1+|(.+)", RegexOptions.Compiled); // RegexOptions.Compiled is optional if you use it more than once
string output = re.Replace(input,
m => (m.Length / m.Result("$1$2").Length) + m.Result("$1$2")); // "2ABC1BC" (case sensitive by default)

Appending a string in a loop in effective way

for long time , I always append a string in the following way.
for example if i want to get all the employee names separated by some symbol , in the below example i opeted for pipe symbol.
string final=string.Empty;
foreach(Employee emp in EmployeeList)
{
final+=emp.Name+"|"; // if i want to separate them by pipe symbol
}
at the end i do a substring and remove the last pipe symbol as it is not required
final=final.Substring(0,final.length-1);
Is there any effective way of doing this.
I don't want to appened the pipe symbol for the last item and do a substring again.
Use string.Join() and a Linq projection with Select() instead:
finalString = string.Join("|", EmployeeList.Select( x=> x.Name));
Three reasons why this approach is better:
It is much more concise and readable
– it expresses intend, not how you
want to achieve your goal (in your
case concatenating strings in a
loop). Using a simple projection with Linq also helps here.
It is optimized by the framework for
performance: In most cases string.Join() will
use a StringBuilder internally, so
you are not creating multiple strings that are
then un-referenced and must be
garbage collected. Also see: Do not
concatenate strings inside loops
You don’t have to worry about special cases. string.Join()
automatically handles the case of
the “last item” after which you do
not want another separator, again
this simplifies your code and makes
it less error prone.
I like using the aggregate function in linq, such as:
string[] words = { "one", "two", "three" };
var res = words.Aggregate((current, next) => current + ", " + next);
You should join your strings.
Example (borrowed from MSDN):
using System;
class Sample {
public static void Main() {
String[] val = {"apple", "orange", "grape", "pear"};
String sep = ", ";
String result;
Console.WriteLine("sep = '{0}'", sep);
Console.WriteLine("val[] = {{'{0}' '{1}' '{2}' '{3}'}}", val[0], val[1], val[2], val[3]);
result = String.Join(sep, val, 1, 2);
Console.WriteLine("String.Join(sep, val, 1, 2) = '{0}'", result);
}
}
For building up like this, a StringBuilder is probably a better choice.
For your final pipe issue, simply leave the last append outside of the loop
int size = EmployeeList.length()
for(int i = 0; i < size - 1; i++)
{
final+=EmployeeList.getEmployee(i).Name+"|";
}
final+=EmployeeList.getEmployee(size-1).Name;

C# preg_replace?

What is the PHP preg_replace in C#?
I have an array of string that I would like to replace by an other array of string. Here is an example in PHP. How can I do something like that in C# without using .Replace("old","new").
$patterns[0] = '/=C0/';
$patterns[1] = '/=E9/';
$patterns[2] = '/=C9/';
$replacements[0] = 'à';
$replacements[1] = 'é';
$replacements[2] = 'é';
return preg_replace($patterns, $replacements, $text);
Real men use regular expressions, but here is an extension method that adds it to String if you wanted it:
public static class ExtensionMethods
{
public static String PregReplace(this String input, string[] pattern, string[] replacements)
{
if (replacements.Length != pattern.Length)
throw new ArgumentException("Replacement and Pattern Arrays must be balanced");
for (var i = 0; i < pattern.Length; i++)
{
input = Regex.Replace(input, pattern[i], replacements[i]);
}
return input;
}
}
You use it like this:
class Program
{
static void Main(string[] args)
{
String[] pattern = new String[4];
String[] replacement = new String[4];
pattern[0] = "Quick";
pattern[1] = "Fox";
pattern[2] = "Jumped";
pattern[3] = "Lazy";
replacement[0] = "Slow";
replacement[1] = "Turtle";
replacement[2] = "Crawled";
replacement[3] = "Dead";
String DemoText = "The Quick Brown Fox Jumped Over the Lazy Dog";
Console.WriteLine(DemoText.PregReplace(pattern, replacement));
}
}
You can use .Select() (in .NET 3.5 and C# 3) to ease applying functions to members of a collection.
stringsList.Select( s => replacementsList.Select( r => s.Replace(s,r) ) );
You don't need regexp support, you just want an easy way to iterate over the arrays.
public static class StringManipulation
{
public static string PregReplace(string input, string[] pattern, string[] replacements)
{
if (replacements.Length != pattern.Length)
throw new ArgumentException("Replacement and Pattern Arrays must be balanced");
for (int i = 0; i < pattern.Length; i++)
{
input = Regex.Replace(input, pattern[i], replacements[i]);
}
return input;
}
}
Here is what I will use. Some code of Jonathan Holland but not in C#3.5 but in C#2.0 :)
Thx all.
You are looking for System.Text.RegularExpressions;
using System.Text.RegularExpressions;
Regex r = new Regex("=C0");
string output = r.Replace(text);
To get PHP's array behaviour the way you have you need multiple instances of `Regex
However, in your example, you'd be much better served by .Replace(old, new), it's much faster than compiling state machines.
Edit: Uhg I just realized this question was for 2.0, but I'll leave it in case you do have access to 3.5.
Just another take on the Linq thing. Now I used List<Char> instead of Char[] but that's just to make it look a little cleaner. There is no IndexOf method on arrays but there is one on List. Why did I need this? Well from what I am guessing, there is no direct correlation between the replacement list and the list of ones to be replaced. Just the index.
So with that in mind, you can do this with Char[] just fine. But when you see the IndexOf method, you have to add in a .ToList() before it.
Like this: someArray.ToList().IndexOf
String text;
List<Char> patternsToReplace;
List<Char> patternsToUse;
patternsToReplace = new List<Char>();
patternsToReplace.Add('a');
patternsToReplace.Add('c');
patternsToUse = new List<Char>();
patternsToUse.Add('X');
patternsToUse.Add('Z');
text = "This is a thing to replace stuff with";
var allAsAndCs = text.ToCharArray()
.Select
(
currentItem => patternsToReplace.Contains(currentItem)
? patternsToUse[patternsToReplace.IndexOf(currentItem)]
: currentItem
)
.ToArray();
text = new String(allAsAndCs);
This just converts the text to a character array, selects through each one. If the current character is not in the replacement list, just send back the character as is. If it is in the replacement list, return the character in the same index of the replacement characters list. Last thing is to create a string from the character array.
using System;
using System.Collections.Generic;
using System.Linq;

Categories

Resources