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
Related
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.
I have a text-file with many lines, each line looks like this:
"string string double double" between each value is a space. I'd like to read out the first string and last double of every line and put these two values in a existing list. That is my code so far, but it doesnt really work.
private void bOpen_Click(object sender, RoutedEventArgs e)
{
bool exists = File.Exists(#"C:\Users\p2\Desktop\Liste.txt");
if (exists == true)
{
StringBuilder sb = new StringBuilder();
using (StreamReader sr = new StreamReader(#"C:\Users\p2\Desktop\Liste.txt"))
{
Vgl comp = new Vgl();
comp.name = Abzahlungsdarlehenrechner.zgName;
comp.gErg = Abzahlungsdarlehenrechner.zgErg;
GlobaleDaten.VglDaten.Add(comp);
int i = 0;
string line = File.ReadLines(#"Liste.txt").Skip(0).Take(1).First();
while ((line = sr.ReadLine()) != null)
{
sb.Append((line));
listBox.Items.Add(line);
GlobaleDaten.VglDaten.Add(comp);
i++;
}
}
}
I have already read this, but it didnt help How do I read specific value[...]
You can try Linq:
var source = File
.ReadLines(#"C:\Users\p2\Desktop\Liste.txt")
.Select(line => line.Split(' '))
.Select(items => new Vgl() {
name = items[0],
gErg = double.Parse(items[3])
});
// If you want to add into existing list
GlobaleDaten.VglDaten.AddRange(source);
// If you want to create a new list
//List<Vgl> list = source.ToList();
how about
List<Vgl> Result = File.ReadLines(#"C:\Users\p2\Desktop\Liste.txt")
.Select(x => new Vgl()
{
name = x.Split(' ').First(),
gErg = decimal.Parse(x.Split(' ').Last(), NumberStyles.AllowCurrencySymbol)
})
.ToList();
I would avoid storing money within doulbe values because this could lead to rounding issues. Use decimal instead. Examples here: Is a double really unsuitable for money?
You can use:
string[] splitBySpace = line.Split(' ');
string first = splitBySpace.ElementAt(0);
decimal last = Convert.ToDecimal(splitBySpace.ElementAt(splitBySpace.Length - 1));
Edit : To Handle Currency symbol:
string[] splitBySpace = line.Split(' ');
string pattern = #"[^0-9\.\,]+";
string first = splitBySpace.ElementAt(0);
string last = (new Regex(pattern)).Split(splitBySpace.ElementAt(splitBySpace.Length - 1))
.FirstOrDefault();
decimal lastDecimal;
bool success = decimal.TryParse(last, out lastDecimal);
I agree with #Dmitry and fubo, if you are looking for alternatives, you could try this.
var source = File
.ReadLines(#"C:\Users\p2\Desktop\Liste.txt")
.Select(line =>
{
var splits = line.Split(' '));
return new Vgl()
{
name = splits[0],
gErg = double.Parse(splits[3])
};
}
use string.split using space as the delimiter on line to the string into an array with each value. Then just access the first and last array element. Of course, if you aren't absolutely certain that each line contains exactly 4 values, you may want to inspect the length of the array to ensure there are at least 4 values.
reference on using split:
https://msdn.microsoft.com/en-us/library/ms228388.aspx
Read the whole file as a string.
Split the string in a foreach loop using \r\n as a row separator. Add each row to a list of strings.
Iterate through that list and split again each record in another loop using space as field separator and put them into another list of strings.
Now you have all the four fields containig one row. Now just use First and Last methods to get the first word and the last number.
I have an MVC app which I need to store information into the database. I get a string value e.g. as
string a = "a,b,c";
I then split the string by removing the commas as
string[] b = a.Split(',');
Now before I save to database I have to add the comma back in and this is where I'm kind of stuck. I can add the comma however one gets added to the end of the string too which I don't want. If I do TrimEnd(',') it removes every comma. Can someone tell me where I'm going wrong please. I'm adding the comma back as:
foreach(var items in b)
{
Console.WriteLine(string.Format("{0},", items));
}
Please note I have to split the comma first due to some validation which needs to be carried out before saving to DB
The expected result should be for example
a,b,c
In stead I get
a,b,c,
Update - The below is the code I'm using In my MVC app after Bruno Garcia answer
string[] checkBoxValues = Request.Form["location"].Split(',');
foreach(var items in checkBoxValues)
{
if (!items.Contains("false"))
{
UsersDto.Location += string.Join(",", items);
}
}
Try:
string.Join(",", b);
This will add a ',' in between each item of your array
Based on the code you posted this is what I think you need
UsersDto.Location = string.Join(
",",
Request.Form["location"]
.Split(',')
.Where(item => !item.Contains("false")));
That will split the values in Request.Form["location"] on comma. Then filter out items that contain "false" as a substring, and finally join them back together with a comma.
So a string like "abc,def,blahfalseblah,xyz" would become "abc,def,xyz".
You can just use String.Join then?
var result = String.join(",", b); // a,b,c
Full document: https://msdn.microsoft.com/en-us/library/57a79xd0(v=vs.110).aspx
it can do
string[] checkBoxValues = Request.Form["location"].Split(',');
string s = "";
foreach (var items in checkBoxValues)
{
if (!items.Contains("false"))
{
s = s + string.Format("{0},", items);
}
}
UsersDto.Location = s.TrimEnd(',');
I want to remove comma separated duplicate string values like :
String str = "2,4,3,12,25,2,4,3,6,2,2,2";
And i want to output like this:
String str1 = "6,2";
please tell how to do this i'll my self but i can't solve this
A wild ride with Linq. Probably there is a better way, but this is the first one I could think of.
string str = "2,4,3,12,25,2,4,3,6,2,2,2";
List<string> uniques = str.Split(',').Reverse().Distinct().Take(2).Reverse().ToList();
string newStr = string.Join(",", uniques);
Console.WriteLine(newStr);
Split the string at the comma to get the sequence
Apply the Reverse op, you get 2 2 2 6 .... 4 2
Apply the Distinct, you get 2,6,3,4,25,12
Take the first 2 elements (2,6)
Reverse them 6,2
Join in a new string with the comma sep.
Pretty basic but works in your case
String str = "2,4,3,12,25,2,4,3,6,2,2,2";
String[] arr = str.Split(',');
String penultimate = "";
String ultimate = "";
for (int i = 0; i < arr.Length; i++)
{
if (arr[i] != ultimate)
{
penultimate = ultimate;
ultimate = arr[i];
}
}
Console.WriteLine("{0},{1}", penultimate, ultimate);
Here is a suggestion:
string item = "";
var lastTwoUnique= str.Split(',') //split the string on ,
//now, take the next element from the array as long as it's
//not equal to the previous element (which we store in item)
.Where((st) => st==item ? false : (item = st) == item) //** see comment below
.Reverse() //reverse collection
.Take(2) //take two (two last)
.Reverse() //reverse back
.ToList(); //make it a list
var answer = string.Join(",", lastTwoUnique);
This solution keeps the data intact, so if you want you could store the unique list, then do many queries on that list. Solutions using Distinct() will, for instance, not keep every occurrence of 2 in the list.
This solution has the intermediate result (after Where) of: 2,4,3,12,25,2,4,3,6,2. While distinct will be:2,4,3,12,25,6
** The line .Where((st) => st==item ? false : (item = st) == item) may seem odd, so let me explain:
Where takes a lambda function that returns true for items that should be taken, and false for the items that should be ignored. So st will become each sub string from the Split.
Now, let's investigate the actual function:
st==item //is this st equal to the previous item?
? false //then return false
: (item = st) == item //if it's not equal, then assign `item` to the current `st`
//and compare that to item and get `true`
You could use the .Distinct() extension method.
String str = "2,4,3,12,25,2,4,3,6,2,2,2";
var oldArray=str.Split(',').Reverse();
var collectionWithDistinctElements = oldArray.Distinct().ToArray();
var reverse=collectionWithDistinctElements.Reverse();
//take two element
var twoElements=reverse.ToList().Take(2);
//last join them
var resultArray=string.Join(",", twoElements);
Another solution, which I've attempted to keep quite simple:
String str = "2,4,3,12,25,2,4,3,6,2,2,2";
var holder = new string[2];
foreach (var x in str.Split(','))
{
if(holder.Last() != x)
{
holder[0] = holder[1];
holder[1] = x;
}
}
var result = string.Join(",", holder);
This will iterate over the comma-separated items, all the time keeping the two last seen distinct items in holder.
String str = "2,4,3,12,25,2,4,3,6,2,2,2";
string str = s1;
var uniques = str.Split(',').Reverse().Distinct().Take(3).Reverse().Take(2).ToList();
string newStr = string.Join(",", uniques.ToArray());
This will give me correct output that is 3,6 thats i want.
Thanks to all the Guys that give me ans.
This will definitely work
string str = "2,4,3,12,25,2,4,3,6,2,2,2";
List<string> uniques = new List<string>()
uniques = str.Split(',').Reverse().Distinct().Take(2).Reverse().ToList();
string newStr = string.Join(",", uniques);
i have a list like this :
List<string> list_lines = new List<string>();
list_lines.add("name1__pass1__com__14__55");
list_lines.add("name2__pass2__com__14__5445");
list_lines.add("name3__pass3__com__14__456456");
list_lines.add("name4__pass4__com__14__1357");
list_lines.add("name5__pass5__com__14__20000");
list_lines.add("name6__pass6__com__14__25");
list_lines.add("name7__pass7__com__14__12");
and more...
as you see there is a separator here -> "__" in every string in that list.
mean :
string[] Separator = new string[] { "__" };
foreach(string s in list_lines)
{
string[] line_ar = s.Split(Separator, StringSplitOptions.None);
int Num = int.parse(line_ar[4]);
}
i want to sort that list by Num parts of that list.
i test some methods using StackOverflow, but there was a bug in them for a big list.
would be really appreciate to help me for soting it
Asc:
list_lines = list_lines.OrderBy(s => int.Parse(s.Split(Separator, StringSplitOptions.None)[4])).ToList();
Desc:
list_lines = list_lines.OrderByDescending(s => int.Parse(s.Split(Separator, StringSplitOptions.None)[4])).ToList();
var myList = list_lines.OrderBy(x => int.Parse(x.Split(new string[] {"__"}, StringSplitOptions.None)[4])).ToList();
If the number always starts after the last underscore character, then this should work:
var sortedList = list_lines
.OrderByDescending(l => int.Parse(l.Substring(l.LastIndexOf("_") + 1)))
.ToList();
The other answers create a new list which is sorted the way you want. If instead you want the same list to be sorted, maybe try something like this:
Func<string, int> getNum = str => int.Parse(str.Split(Separator, StringSplitOptions.None)[4]);
list_lines.Sort((x, y) => getNum(x).CompareTo(getNum(y)));
This uses an overload of List<>.Sort. If you want descending order, swap x and y in the Comparison<> lambda body.
If your list is very long, this is faster (uses Quick Sort) and doesn't require the memory of a new copy of the list.
You can take advantage of lambda expression in LINQ functions like OrderBy
string[] Separator = new string[] { "__" };
var sortedList = list_lines
.OrderBy(s => int.Parse(s.Split(Separator, StringSplitOptions.None)[4]))
.ToList();
As an unrelated side note, please use correct C# naming conventions so your code is easier to read and is unified with existing C# code-base. E.g. not beginning local variable names with capital letter (Separator -> separator) and using lower camel case (Pascal case) in case it contains more words (list_lines -> listLines)
Forgive me for answering a related question here:
Sat 2020-03-21 06:03:31.129: 03: [100001] Player 1
Sat 2020-03-21 06:03:33.119: 02: [620524] Player 22
I would like to first sort the list by: 1) The number within the two [] 2) The date up until the : nn:
Here's one way (of many ways) to do it:
void Main()
{
var originalList = new List<string>
{
#"Sat 2020-03-21 06:03:31.129: 03: [100001] Player 1",
#"Sat 2020-03-21 06:03:33.119: 02: [620524] Player 22",
};
var sortableList = originalList.Select(x => splitTheLine(x));
var result = sortableList.OrderBy(x => x.numberPart).ThenBy(x => x.datePart).Select(x => x.wholeString);
}
(DateTime datePart, int numberPart, string wholeString) splitTheLine(string x)
{
string[] separator = { "[", "]", ": " };
var result = x.Split(separator, StringSplitOptions.None);
return (DateTime.Parse(result[0]), int.Parse(result[3]), x );
}
I define a method splitTheLine to extract the date and number parts along with the original string. It returns a tuple. Then I use the method with the select operator of LINQ to retrieve a list with three "columns". Again with LINQ, using the OrderByand ThenByoperators I sort the list. Finally I selectonly the originial string for the result.
This solution can be shortened a lot - but at the cost of readability, as usual.