I have a string of comma separated values, to get a string array from this I use
string[] values = value.Split(',');
I want to trim all these values by creating a new list of string and calling a foreach on the array like this
List<string> trimmedValues = new List<string>();
foreach (string str in values)
trimmedValues.Add(str.Trim());
Is there a more efficent way to do this with less code say by calling a method on the array itself?
Use linq
List<string> trimmedValues = values.Select(v => v.trim()).toList()
Try this :
var myTrimResult = "a ,b , c ".Split(',').Select(x => x.Trim());
The "myTrimResult" variable will contain trimmed elements.
To effectively reduce code bloat, I suggest to use an extension.
Declare a method like the following, in a common context in your project (or even better, in an external helper DLL to carry among different projects):
public static List<string> TrimList(this string[] array)
{
var list = new List<string>();
foreach (var s in array)
{
list.Add(s.Trim());
}
return list;
}
Now, in your code, you can simply use:
var trimmedValues = values.TrimList();
I find it more readable than using LINQ expression in code
Related
I have following string in my aspx.cs page. These both strings are dynamic
string fromDB = "12,24,25,45,67,78,90" (its a dynamic string)
I have another string which has two or more values always as given below
string anotherStr = "24,67"
I am not getting an idea how to remove "anotherStr" values from "fromDB"
Finally I need "12,25,45,78,90". I am not getting an idea how to do this using c#.
using Linq:
string.Join(",", fromDB.Split(',').Except(anotherStr.Split(',')))
Split your (hard) problem into multiple (easy) problems:
Convert your comma-separated strings into lists (or arrays) of strings (using e.g. String.Split).
Find out how to remove all list entries from one list from a second list (using e.g. Enumerable.Except).
Convert your list back into a comma-separated string (using e.g. String.Join).
For all of these simpler problems, solutions can be found here on SO.
string fromDB = "12,24,25,45,67,78,90";
string anotherStr = "24,67";
var result = fromDB.Split(',').Except(anotherStr.Split(',')).ToList();
Console.WriteLine(string.Join(",", result));
Console.ReadLine();
This splits the strings into arrays, and then excludes any entries from fromDB that are also in anotherStr.
Note that the use of Except means that any duplicates will be removed from fromDB - as per https://stackoverflow.com/a/44547153/34092 .
You could do something like
HashSet<string> all = new HashSet<string>(fromDB.Split(',')),
toRemove = new HashSet<string>(anotherStr.Split(','));
foreach(var item in toRemove) {
all.Remove(item);
}
I suggest using HashSet<T> and Linq:
HashSet<string> exclude = new HashSet<string>(anotherStr.Split(','));
string result = string.Join(",", fromDB
.Split(',')
.Where(item => !exclude.Contains(item)));
Please, notice, that Except removes duplicates within fromDB while Where preserves them.
You split both strings to get two arrays, making the first a List<string> :
var fromDbList = fromDb.Split(',').ToList();
var anotherStrArray = anotherStr.Split(',');
You loop the second array, and delete its values from the first (which you cannot do on a String[], hence the previous ToList())
foreach (var valueToDelete in anotherStrArray)
{
fromDbList.Remove(valueToDelete);
}
Then you join the (now modified) first array to get a single string:
var finalString = String.Join(fromDbList, ",");
I tried searching by "C# new string array pass dynamic" but could not find anything relevant.
int[] IDs = someMethodCall();
List<string> values = new List<string>();
foreach (int i in IDs)
{
values.Add(i.ToString());
}
someClass sc = new someClass();
sc.Value = new string[] { "values.string1", "values.string2", ... };
What I'm trying to do is to pass the strings from values to sc.Value, so I don't have to write them out (since I don't what they'll be beforehand).
sc.Value is a string[] as defined by the class I'm using from an API (not written by me).
What is the best way to do this dynamically? In other words, how to pass in dynamic values to a string[] construction?
If I'm not missing something,you can just use ToArray method
sc.Value = values.ToArray();
BTW, you don't even need to create a list in the first place:
sc.Value = someMethodCall().Select(x => x.ToString()).ToArray();
I'm a little confused by the way you word your questioning, but I think you are trying to send your list to an array, which is easily done using the code below:
List<string> values = new List<string>();
sc.Value = values.ToArray();
How about just using the built-in method ToArray:
sc.Value = values.ToArray();
Comes with List, and is an extension method for IEnumerable if you can use LINQ.
I have a list of comma separated string like below:
List<string> IdList=new List<string>();
and each element of list has comma separated string like
1,2,4,5,6,7,8,10,12,15,16
2,3,5,7,8,9,0,10,16,17
4,5,89,12,13,1,2,3,6,7,10,16
I want to apply AND operation on this list of string so I get output like below:
2,5,7,10,16
Is there any efficient way to implement Intersection operation?
You're actually looking for an intersection.
If you don't need the values in numeric order, you could just treat each string as just comma-separated values. Start with the first list, and just intersect each other one appropriately:
HashSet<string> set = new HashSet<string>(list[0].Split(','));
foreach (var item in list.Skip(1))
{
set.IntersectWith(item.Split(','));
}
string result = string.Join(",", set);
Complete sample code:
using System;
using System.Collections.Generic;
using System.Linq;
class Test
{
static void Main()
{
var list = new List<string>
{
"1,2,4,5,6,7,8,10,12,15,16",
"2,3,5,7,8,9,0,10,16,17",
"4,5,89,12,13,1,2,3,6,7,10,16"
};
HashSet<string> set = new HashSet<string>(list[0].Split(','));
foreach (var item in list.Skip(1))
{
set.IntersectWith(item.Split(','));
}
string result = string.Join(",", set);
Console.WriteLine(result);
}
}
Result (order not guaranteed):
2,5,7,10,16
I don't know about "less memory utilization", but my first shot at this would be something along these lines (untested, coded in browser, no Visual Studio handy yadda yadda):
Dictionary<int,int> occurences = new Dictionary<int,int>();
int numberOfLists = YourCollectionOfOuterLists.Count;
foreach (string list in YourCollectionOfOuterLists) {
foreach (string value in list.Split(',')) {
occurences[value] = ((occurences[value] as int) ?? 0) + 1;
}
}
List<int> output = new List<int>();
foreach (int key in occurences.Keys) {
if (occurences[key] == numberOfLists) {
output.Add(key);
}
}
return String.Join(output.Select(x => x.ToString()), ",");
It might very well be possible to write the code more tersely, but anything that accomplishes what you seem to be after will still have to perform roughly the same steps: decide which elements exist in all lists (which is slightly non-trivial as the number of lists is unknown), then make a new list out of those values.
If you have access to it, something like Parallel.ForEach() might help cut down on wallclock execution time at least of the second loop (and possibly the first, with proper locking/synchronization in place).
If you are after something other than this, please clarify your question to describe exactly what you want.
I'm not sure about performance but you can use the Aggregate extension method to 'fold intersections'.
var data = new List<string>
{
"1,2,4,5,6,7,8,10,12,15,16",
"2,3,5,7,8,9,0,10,16,17",
"4,5,89,12,13,1,2,3,6,7,10,16",
};
var fold = data.Aggregate(data[0].Split(',').AsEnumerable(), (d1, d2) => d1.Intersect(d2.Split(',')));
The goal is to sort through a text (i.e. a speech) and output a list of the distinct words in the speech to a textbox. I have read through a lot of tips on the boards and played around a lot but at this point am at that point where I am more confused then when I started. Here is my code
private void GenerateList(string[] wordlist)
{
List<string> wordList = new List<string>();
for (int i = 0; i < wordlist.Length; i++)
{
wordList.Add(wordlist[i]);
}
var uniqueStr = from item in wordList.Distinct().ToList()
orderby item
select item;
for (int i = 0; i < uniqueStr.Count(); i++ )
{
txtOutput.Text = uniqueStr.ElementAt(i) + "\n";
}
}
At this point I am getting a return of one word. For the text I am using (the gettysburg address) it is the word "year" and it is the only instance of that word in the text.
I am passing the function each individual word loaded into a string array that is then put into a list (which may be redundant?).
I hope this does what you need in a simple and efficient manner (using .Dump() from LINQPad)
void Main()
{
// can be any IEnumerable<string> including string[]
var words = new List<string>{"one", "two", "four", "three", "four", "a", "z"};
words.ToDistinctList().Dump();
// you would use txtOutput.Text = words.ToDistinctList()
}
static class StringHelpers
{
public static string ToDistinctList(this IEnumerable<string> words)
{
return string.Join("\n", new SortedSet<string>(words));
}
}
A few tips regarding your question:
There is no reason to turn the array into list, because LINQ extension methods are defined on IEnumerable<T>, which is implemented by both the array and the list
Make sure that all letters are in the same case - use ToLower, for instance
You are overwriting txtOutput.Text in every iteration. Instead of setting the new value, append new part to the existing value
Here is the simple piece of code which produces the output you wanted:
IEnumerable<string> distinct =
wordList
.Select(word => word.ToLower())
.Distinct()
.OrderBy(word => word);
txtOutput.Text = string.Join("\n", distinct.ToArray());
On a related note, here is a very simple LINQ expression which returns distinct words from a text, where the whole text is specified as one string:
public static IEnumerable<string> SplitIntoWords(this string text)
{
string pattern = #"\b[\p{L}]+\b";
return
Regex.Matches(text, pattern)
.Cast<Match>() // Extract matches
.Select(match => match.Value.ToLower()) // Change to same case
.Distinct(); // Remove duplicates
}
You can find more variations of regex pattern for the same problem here: Regex and LINQ Query to Split Text into Distinct Words
Here's how I'd simplify your code, as well as achieve what you want to achieve.
private void GenerateList(string[] wordlist)
{
List<string> wordList = wordlist.ToList(); // initialize the list passing in the array
var uniqueStr = from item in wordList.Distinct().ToList()
orderby item
select item;
txtOutput.Text = String.Join("\n", uniqueStr.ToArray());
}
You can use the fact that the StringBuilder class has a fluent interface along with LINQ to simplify this greatly.
First, you can create the StringBuilder and concatenate all of the words into the same instance like so:
// The builder.
var builder = new StringBuilder();
// A copy of the builder *reference*.
var builderCopy = builder;
// Get the distinct list, order by the string.
builder = wordList
// Get the distinct elements.
.Distinct()
// Order the words.
.OrderBy(w => w).
// Append the builder.
Select(w => builderCopy.AppendLine(word)).
// Get the last or default element, this will
// cycle through all of the elements.
LastOrDefault();
// If the builder is not null, then assign to the output, otherwise,
// assign null.
txtOutput.Text = builder == null ? null : builder.ToString();
Note, you don't have to actually materialize the list, as wordList is already a materialized list, it's an array (and as a side note, typed arrays in C# implement the IList<T> interface).
The AppendLine method (and most of the methods on StringBuilder) return the instance of the StringBuilder that the operation was performed on, which is why the LastOrDefault method call works; simply call the operation and return the result (each item returned will be the same reference).
The builderCopy variable is used to avoid access to a modified closure (it never hurts to be safe).
The null check at the end is for the case where wordList doesn't contain any elements. In this case, the call to LastOrDefault will return null.
I have a list of strings in C#, and want to create a list of unique characters that are in the strings in the list, using LINQ.
I have so far worked out how to turn the List into a List, but I can't work out how to get the LINQ to go further than that.
What I have so far is as follows:
List<string> dictionary = new List<string>(someArray);
List<string[]> uniqueCharacters = dictionary.ConvertAll(s => s.Split());
I believe I need to something along the lines of
List<char> uniqueCharacters =
dictionary.ConvertAll(s => s.Split()).SelectAll(t, i=>t[i][0]);
You can use LINQ's SelectMany method, e.g.:
var list = new List<string> { "Foo", "Bar" };
var chars = list.SelectMany(s => s.ToCharArray());
var distinct = chars.Distinct();
Get your LinQ result and put it in loop, compare every char with in list of char.
foreach (string character in dictionary)
{
if (!(uniqueCharacters).Contains(character))
{
uniqueCharacters.Add(character);
}
}