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, ",");
Related
I am getting the error System.Collections.Generic.List`1[System.String] when i try to use String.Join in a list of result.
For instance i have two list like this:
var list1= new List<string>{"string1","string2"};
var list2= new List<string>{"string1"};
Then i want to get a message with the string that doesn't appear on list2
var resultList1 = list1.Except(list2).ToList(); // this line get a list with "string2"
when i use String.Join i get the error System.Collections.Generic.List`1[System.String]. Also i tried resultList1.Cast<List>() instead resultList1 with same outcome.
var message = "List strings not found:\n\n"
+ String.Join(",", $"\n\n{resultList1}\n\n");
You need to use the string join like ths,
var message = "List strings not found:\n\n" + String.Join(",", resultList1);
You are using the system join on an enumerable array but when you use $"\n\n{result1}\n\n" string interpolation, you are basically joining a single string which doesn't work.
String.Join takes in a string (comma, newline or any string) that combines all elements from an array but when you give string instead of array or collection, it will give the error.
Lastly, Documentation should help explain more about the usage in depth.
Edit: I changed my inputs from a
List<string>
to a List<int>. They should always be valid integers now, no empty/null etc.
I currently have a 6 item list, the items consistent of integers.
I also have an object that contains a coma delimited string of integers. I'm trying to match the inputs to this list.
For example
Inputs could be, 1000,2000,3000
The object contains 1000,2000,3000,4000
I would want this to match.
If my input is 1000,2000,3000,4000 and my object only contains 1000,2000,3000 -> it should not match.
Here's my current code to create the object using linq to xml. "TaxUnitIdList" is the comma delimited string. (This is when my inputs were strings)
var obj = (from tug in tugElem.Descendants("CodeData")
select new TaxUnitGroups
{
Code = (string)tug.Attribute("code"),
CodeID = (string)tug.Attribute("codeid"),
Desc = (string)tug.Attribute("desc"),
TaxUnitIdList = (string)tug.Attribute("taxunits")
});
I'm thinking something along the following or a join (which I could not get to work) this is failing me due to the where wanting a boolean (which makes sense)
var matchedTugs = (from tug in tugElem.Descendants("CodeData")
let TaxUnitIdList = (string)tug.Attribute("taxunits")
let taxArr = TaxUnitIdList.Split(',').Select(int.Parse)
where taxArr.Contains(inputTaxUnits.All()) //This is where I screw up
select new TaxUnitGroups
{
Code = (string)tug.Attribute("code"),
CodeID = (string)tug.Attribute("codeid"),
Desc = (string)tug.Attribute("desc"),
TaxUnitIdList = (string)tug.Attribute("taxunits")
}).ToList();
Try this in the Where clause:
TaxUnitIdList.Split(',')
.Select(s => int.Parse(s))
.Except(inputTaxUnits.Where(s=>int.TryParse(s, out tempInteger))
.Select(s=>int.Parse(s)))
.Any();
Basically, we want to covert the TaxUnitId list into an integer array, convert the input list into a good (tryparse) input array as well, find the difference and verify that the result is 0.
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
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);
}
}