How can I trim all elements in a list? - c#

I'm trying the following
string tl = " aaa, bbb, ccc, dddd eeeee";
var tags = new List<string>();
tags.AddRange(tl.Split(','));
tags.ForEach(x => x = x.Trim().TrimStart().TrimEnd());
var result = String.Join(",", tags.ToArray());
But it doesn't work, the tags always come back as " aaa", " bbb".
How can I trim all elements in a list?

// you can omit the final ToArray call if you're using .NET 4
var result = string.Join(",", tl.Split(',').Select(s => s.Trim()).ToArray());
If you only need the final result string, rather than the intermediate collection, then you could use a regular expression to tidy the string. You'll need to benchmark to determine whether or not the regex outperforms the split-trim-join technique:
var result = Regex.Replace(tl, #"(?<=^|,) +| +(?=,|$)", "");

Ran into the same problem. #Lee already explained that Lamda .ForEach() uses a copy.
You can write an Extension Method like this and use a for loop (foreach also not possible):
public static class StringListExtensions
{
public static void TrimAll(this List<string> stringList)
{
for (int i = 0; i < stringList.Count; i++)
{
stringList[i] = stringList[i].Trim(); //warning: do not change this to lambda expression (.ForEach() uses a copy)
}
}
}
Use it like this:
var productNumbers = new List<string>(){ "11111", " 22222 " }
productNumbers.TrimAll();
should result in: List(){ "11111", "22222" }
I didn't use the split and re-join solution (chosen solution) because there can be a comma inside one of the string items. The regex version is not self explanatory. This is old-school but safer and can be easily understood...

The reason your approach doesn't work is that the x is a copy of the current string reference being processed in the ForEach call (i.e. local to the delegate). Therefore the assignment doesn't affect the item referenced in the list.

Try
List<string> lstSelect = string_test.Split(',').Select(x => x.Trim()).ToList();

What's going on is that you're trying to modify a collection using a foreach statement- which is a no-no. Collections cannot be modified with a foreach.
You'll need to modifiy it a for loop, or, using lambdas, you can use LukeH's solution.

Your problem is that there is no comma between dddd and eeeee. If you want those to be separate, you need to split on ' ', strip the commas, and then trim extra whitespace.
string tl = " aaa, bbb, ccc, dddd eeeee";
var result = t1.Split(' ').Where(s => !String.IsNullOrEmpty())
.Select(s => s.Replace(',','').Trim())
.ToArray();

This can be easily done through LINQ one liner:
Just remember rule of Thumb :
SELECT -> For transforming the elements
WHERE -> For Filtering the elements
Now, we can use the SELECT clause to Transform all the elements:
List<string> listString = new List<string>(){"abc ", "xyz ", " Abc ", " zx"};
listString = listString.Select(x => x.Trim()).ToList();
Thats all and things are done.

Related

Unity Lists Finding 2 letters in a list containing 5 letter words [duplicate]

I have a list like so and I want to be able to search within this list for a substring coming from another string. Example:
List<string> list = new List<string>();
string srch = "There";
list.Add("1234 - Hello");
list.Add("4234 - There");
list.Add("2342 - World");
I want to search for "There" within my list and return "4234 - There". I've tried:
var mySearch = list.FindAll(S => s.substring(srch));
foreach(var temp in mySearch)
{
string result = temp;
}
With Linq, just retrieving the first result:
string result = list.FirstOrDefault(s => s.Contains(srch));
To do this w/o Linq (e.g. for earlier .NET version such as .NET 2.0) you can use List<T>'s FindAll method, which in this case would return all items in the list that contain the search term:
var resultList = list.FindAll(delegate(string s) { return s.Contains(srch); });
To return all th entries:
IEnumerable<string> result = list.Where(s => s.Contains(search));
Only the first one:
string result = list.FirstOrDefault(s => s.Contains(search));
What you've written causes the compile error
The best overloaded method match for 'string.Substring(int)' has some invalid arguments
Substring is used to get part of string using character position and/or length of the resultant string.
for example
srch.Substring(1, 3) returns the string "her"
As other have mentioned you should use Contains which tells you if one string occurs within another. If you wanted to know the actual position you'd use IndexOf
same problem i had to do.
You need this:
myList.Where(listStrinEntry => myString.IndexOf(listStringEntry) != -1)
Where:
myList is List<String> has the values
that myString has to contain at any position
So de facto you search if myString contains any of the entries from the list.
Hope this is what you wanted...
i like to use indexOf or contains
someString.IndexOf("this");
someString.Contains("this");
And for CaseSensitive use:
YourObj yourobj = list.FirstOrDefault(obj => obj.SomeString.ToLower().Contains("some substring"));
OR
YourObj yourobj = list.FirstOrDefault(obj => obj.SomeString.ToUpper().Contains("some substring"));

How to compare list of strings to a string where elements in the list might have letters be scrambled up?

I'm trying to write a lambda expression to compare members of a list to a string, but I also need to catch elements in the list that might have their letter scrambled up.
Here's code I got right now
List<string> listOfWords = new List<String>() { "abc", "test", "teest", "tset"};
var word = "test";
var results = listOfWords.Where(s => s == word);
foreach (var i in results)
{
Console.Write(i);
}
So this code will find string "test" in the list and will print it out, but I also want it to catch cases like "tset". Is this possible to do easily with linq or do I have to use loops?
How about sorting the letters and seeing if the resulting sorted sequences of chars are equal?
var wordSorted = word.OrderBy(c=>c);
listOfWords.Where(w => w.OrderBy(c=>c).SequenceEqual(wordSorted));

C# Split - Split on list dont return all the wanted strings

I'm fairly new to C#, and i've come across a problem trying to split on list elements.
I have a resource file containing string properties as such:
ResourceFile
ResourceFile
I've collected them in a List as:
public List<String> RawNewsList1 = new List<String>()
{
{Resource.NewsContentAndroid1},
{Resource.NewsMetaAndroid1},
};
I'm trying to split on the semicolons but only get results from my second list item.
My split look like this:
public void FilterRawNews()
{
String[] seperator = { ";;;" };
String[] filteredList1 = { "" };
for (int i = 0; i < RawNewsList1.Count; i++) {
filteredList1 = RawNewsList1[i].Split(seperator, 5,
StringSplitOptions.RemoveEmptyEntries);
}
foreach (String s in filteredList1)
{
Console.WriteLine(s);
}
}
Its only prints:
110
2.8
02-07-2020
What am i doing wrong?
Thanks in advance!
The filteredList1 variable is first filled with data from your the first resource, then at the next loop the variable's content is replaced with the data coming from the second resource.
You can use a List<string> instead that has the AddRange method to continuosly add elements to the list
List<string> filteredList1 = new List<string>();
for (int i = 0; i < RawNewsList1.Count; i++) {
filteredList1.AddRange(RawNewsList1[i].Split(seperator, 5,StringSplitOptions.RemoveEmptyEntries));
}
From this we could simplify the code to one-liner with
filteredList = RawNewsList1.SelectMany(a => a.Split(seperator,5, StringSplitOptions.RemoveEmptyEntries)).ToList();
So, what's happen in that single line? That syntax is used when you work with objects that can be treated as a sequence of data. In this context your array RawNewsList1 is a sequence of data and we can use the IEnumerable extensions brought to us by using the Linq namespace. The SelectMany extension requires a lambda expression ( a => ....) that is used to produce the instructions where each element of the sequence (a) is passed to an expression that returns another sequence of data (the array returned by Split). The sequence returned is accumulated to the sequence produced by the next elements from the original RasNewsList1. Finally the accumulated sequence is materialized with the call to ToList()
You are overwriting filteredList1 in each iteration.
That is why you only get the last result.
Just declare filteredList1 as a list and and use AddRange().
Edit: or use LINQ:
var raw = new List<string>() { "111;;;222", "333;;;444" };
String[] seperator = { ";;;" };
var filterlist1 = raw.SelectMany(r => r.Split(seperator, 5, StringSplitOptions.RemoveEmptyEntries)).ToList();

Find substring in a list of strings

I have a list like so and I want to be able to search within this list for a substring coming from another string. Example:
List<string> list = new List<string>();
string srch = "There";
list.Add("1234 - Hello");
list.Add("4234 - There");
list.Add("2342 - World");
I want to search for "There" within my list and return "4234 - There". I've tried:
var mySearch = list.FindAll(S => s.substring(srch));
foreach(var temp in mySearch)
{
string result = temp;
}
With Linq, just retrieving the first result:
string result = list.FirstOrDefault(s => s.Contains(srch));
To do this w/o Linq (e.g. for earlier .NET version such as .NET 2.0) you can use List<T>'s FindAll method, which in this case would return all items in the list that contain the search term:
var resultList = list.FindAll(delegate(string s) { return s.Contains(srch); });
To return all th entries:
IEnumerable<string> result = list.Where(s => s.Contains(search));
Only the first one:
string result = list.FirstOrDefault(s => s.Contains(search));
What you've written causes the compile error
The best overloaded method match for 'string.Substring(int)' has some invalid arguments
Substring is used to get part of string using character position and/or length of the resultant string.
for example
srch.Substring(1, 3) returns the string "her"
As other have mentioned you should use Contains which tells you if one string occurs within another. If you wanted to know the actual position you'd use IndexOf
same problem i had to do.
You need this:
myList.Where(listStrinEntry => myString.IndexOf(listStringEntry) != -1)
Where:
myList is List<String> has the values
that myString has to contain at any position
So de facto you search if myString contains any of the entries from the list.
Hope this is what you wanted...
i like to use indexOf or contains
someString.IndexOf("this");
someString.Contains("this");
And for CaseSensitive use:
YourObj yourobj = list.FirstOrDefault(obj => obj.SomeString.ToLower().Contains("some substring"));
OR
YourObj yourobj = list.FirstOrDefault(obj => obj.SomeString.ToUpper().Contains("some substring"));

Merge two (or more) lists into one, in C# .NET

Is it possible to convert two or more lists into one single list, in .NET using C#?
For example,
public static List<Product> GetAllProducts(int categoryId){ .... }
.
.
.
var productCollection1 = GetAllProducts(CategoryId1);
var productCollection2 = GetAllProducts(CategoryId2);
var productCollection3 = GetAllProducts(CategoryId3);
You can use the LINQ Concat and ToList methods:
var allProducts = productCollection1.Concat(productCollection2)
.Concat(productCollection3)
.ToList();
Note that there are more efficient ways to do this - the above will basically loop through all the entries, creating a dynamically sized buffer. As you can predict the size to start with, you don't need this dynamic sizing... so you could use:
var allProducts = new List<Product>(productCollection1.Count +
productCollection2.Count +
productCollection3.Count);
allProducts.AddRange(productCollection1);
allProducts.AddRange(productCollection2);
allProducts.AddRange(productCollection3);
(AddRange is special-cased for ICollection<T> for efficiency.)
I wouldn't take this approach unless you really have to though.
Assuming you want a list containing all of the products for the specified category-Ids, you can treat your query as a projection followed by a flattening operation. There's a LINQ operator that does that: SelectMany.
// implicitly List<Product>
var products = new[] { CategoryId1, CategoryId2, CategoryId3 }
.SelectMany(id => GetAllProducts(id))
.ToList();
In C# 4, you can shorten the SelectMany to: .SelectMany(GetAllProducts)
If you already have lists representing the products for each Id, then what you need is a concatenation, as others point out.
you can combine them using LINQ:
list = list1.Concat(list2).Concat(list3).ToList();
the more traditional approach of using List.AddRange() might be more efficient though.
List.AddRange will change (mutate) an existing list by adding additional elements:
list1.AddRange(list2); // list1 now also has list2's items appended to it.
Alternatively, in modern immutable style, you can project out a new list without changing the existing lists:
Concat, which presents an unordered sequence of list1's items, followed by list2's items:
var concatenated = list1.Concat(list2).ToList();
Not quite the same, Union projects a distinct sequence of items:
var distinct = list1.Union(list2).ToList();
Note that for the 'value type distinct' behaviour of Union to work on reference types, that you will need to define equality comparisons for your classes (or alternatively use the built in comparators of record types).
You could use the Concat extension method:
var result = productCollection1
.Concat(productCollection2)
.Concat(productCollection3)
.ToList();
I know this is an old question I thought I might just add my 2 cents.
If you have a List<Something>[] you can join them using Aggregate
public List<TType> Concat<TType>(params List<TType>[] lists)
{
var result = lists.Aggregate(new List<TType>(), (x, y) => x.Concat(y).ToList());
return result;
}
Hope this helps.
list4 = list1.Concat(list2).Concat(list3).ToList();
// I would make it a little bit more simple
var products = new List<List<product>> {item1, item2, item3 }.SelectMany(id => id).ToList();
This way it is a multi dimensional List and the .SelectMany() will flatten it into a IEnumerable of product then I use the .ToList() method after.
I've already commented it but I still think is a valid option, just test if in your environment is better one solution or the other. In my particular case, using source.ForEach(p => dest.Add(p)) performs better than the classic AddRange but I've not investigated why at the low level.
You can see an example code here: https://gist.github.com/mcliment/4690433
So the option would be:
var allProducts = new List<Product>(productCollection1.Count +
productCollection2.Count +
productCollection3.Count);
productCollection1.ForEach(p => allProducts.Add(p));
productCollection2.ForEach(p => allProducts.Add(p));
productCollection3.ForEach(p => allProducts.Add(p));
Test it to see if it works for you.
Disclaimer: I'm not advocating for this solution, I find Concat the most clear one. I just stated -in my discussion with Jon- that in my machine this case performs better than AddRange, but he says, with far more knowledge than I, that this does not make sense. There's the gist if you want to compare.
To merge or Combine to Lists into a One list.
There is one thing that must be true: the type of both list will be
equal.
For Example: if we have list of string so we can add add another list to the
existing list which have list of type string otherwise we can't.
Example:
class Program
{
static void Main(string[] args)
{
List<string> CustomerList_One = new List<string>
{
"James",
"Scott",
"Mark",
"John",
"Sara",
"Mary",
"William",
"Broad",
"Ben",
"Rich",
"Hack",
"Bob"
};
List<string> CustomerList_Two = new List<string>
{
"Perter",
"Parker",
"Bond",
"been",
"Bilbo",
"Cooper"
};
// Adding all contents of CustomerList_Two to CustomerList_One.
CustomerList_One.AddRange(CustomerList_Two);
// Creating another Listlist and assigning all Contents of CustomerList_One.
List<string> AllCustomers = new List<string>();
foreach (var item in CustomerList_One)
{
AllCustomers.Add(item);
}
// Removing CustomerList_One & CustomerList_Two.
CustomerList_One = null;
CustomerList_Two = null;
// CustomerList_One & CustomerList_Two -- (Garbage Collected)
GC.Collect();
Console.WriteLine("Total No. of Customers : " + AllCustomers.Count());
Console.WriteLine("-------------------------------------------------");
foreach (var customer in AllCustomers)
{
Console.WriteLine("Customer : " + customer);
}
Console.WriteLine("-------------------------------------------------");
}
}
In the special case: "All elements of List1 goes to a new List2": (e.g. a string list)
List<string> list2 = new List<string>(list1);
In this case, list2 is generated with all elements from list1.
You need to use Concat operation
When you got few list but you don't know how many exactly, use this:
listsOfProducts contains few lists filled with objects.
List<Product> productListMerged = new List<Product>();
listsOfProducts.ForEach(q => q.ForEach(e => productListMerged.Add(e)));
If you have an empty list and you want to merge it with a filled list, do not use Concat, use AddRange instead.
List<MyT> finalList = new ();
List<MyT> list = new List<MyT>() { a = 1, b = 2, c = 3 };
finalList.AddRange(list);

Categories