Linq lambda foreach - c#

Trying for wrap each string in array but it doesn't works, means foreach loop, please explain why
string s = "keepsakes,table runners,outdoor accessories";
List<string> keys = s.Split(',').ToList();
keys.ForEach(x => x = String.Concat("%", x, "%"));
s = String.Join(",", keys);
Console.WriteLine(s);
need to get "%keepsakes%,%table runners%,%outdoor accessories%"
UPD:
Thanks a lot for suggestions(it's a same way)
but some one can answer why this is works and not works under:
object
public class MyItems
{
public string Item { get; set; }
}
and func
string s = "keepsakes,table runners,outdoor accessories";
List<MyItems> keys = s.Split(',').ToList().Select(x => new MyItems(){ Item = x }).ToList();
keys.ForEach(x => x.Item = String.Concat("%", x.Item, "%"));
s = String.Join(",", keys.Select(x => x.Item).ToList());
Console.WriteLine(s);

You are not modifying the list within the ForEach, you are just creating strings that are assigned to the local variable x but then thrown away. You could use a for-loop:
for(int i = 0; i < keys.Count; i++)
{
keys[i] = String.Concat("%", keys[i], "%");
}
For what it's worth, here the shorter LINQ version which also circumvents the core issue:
s = string.Join(",", s.Split(',').Select(str => "%" + str + "%"));

You can use Join and Select and Format
string s = "keepsakes,table runners,outdoor accessories";
var output = string.Join(",", s.Split(',').Select(x => string.Format("%{0}%", x)));

you can do easier: replace each comma with %,%
string s = "keepsakes,table runners,outdoor accessories";
string s2 = "%" + s.Replace("," , "%,%") + "%";

Another approach could be using Regex instead of LINQ:
string s = "keepsakes,table runners,outdoor accessories";
string pattern = "\\,+";
string replacement = "%,";
Regex rgx = new Regex(pattern);
string result = string.Format("%{0}%", rgx.Replace(s, replacement));
Edit:
The reason why it works using a class to assign the string it is because when you use the foreach in your first instance:
keys.ForEach(x => x = String.Concat("%", x, "%"));
x, elements of keys, which is a string, is a reference passed by value to the function ForEach. Take this as an example:
var myString = "I'm a string";
Console.WriteLine(myString);
ChangeValue(myString);
Console.WriteLine(myString);
void ChangeValue(string s)
{
s = "something else";
}
If you run that snippet you'll see that myString won't be changed inside the method ChangeValue because we are trying to replace the reference. The same thing happens for the method ForEach, this is the main reason you cannot change the value of your list within the ForEach.
Instead if you do:
class MyClass{
public string aString;
}
void ChangeValue(MyClass s)
{
s.aString = "something else";
}
var myClass = new MyClass();
myClass.aString = "I'm a string";
Console.WriteLine(myClass.aString);
ChangeValue(myClass);
Console.WriteLine(myClass.aString);
You acknowledge that in the second Console.WriteLine the value of the field aString will be changed to "something else". Here is a good explanation of how reference types are passed by value

Just another approach (without lambdas):
string result = string.Concat("%", s, "%").Replace(",", "%,%");

List<>.ForEach cannot be used to change the contents of the list. You can either create a new list or use a for loop.
keys = keys.Select(x => "%" + x + "%").ToList();
or
for(int i = 0; i < keys.Count; i++)
{
keys[i] = "%" + keys[i] + "%";
}

As others have noted, the lambda passed to List.ForEach does not return a value.
LINQ is lazy, but String.Join will force enumeration:
var res = String.Join(",", input.Split(',').Select(s => "%" + s + "%"));

The ForEach doesn't change your list of string, it will only perform an action using each string. Instead you can do it this way :
string s = "keepsakes,table runners,outdoor accessories";
List<string> keys = s.Split(',').Select(x => String.Concat("%", x, "%")).ToList();
s = String.Join(",", keys);
Console.WriteLine(s);

Related

How to make string list to "string array"

This is what I want to convernt: {"apple", "banana"} to "["apple", "banana"]"
I have tried convert string list to string array first, then convert string array to string, but did not work.
var testing = new List<string> {"apple", "banana"};
var arrayTesting = testing.ToArray();
var result = arrayTesting.ToString();
You can use string.Join(String, String[]) method like below to get a , separated string values (like csv format)
var stringifiedResult = string.Join(",", result);
You can try this, should work;
var testing = new List<string> { "apple", "banana" };
var arrayTesting = testing.ToArray<string>();
var result = string.Join(",", arrayTesting);
You can also use StringBuilder
StringBuilder sb = new StringBuilder();
sb.Append("\"[");
for (int i = 0; i < arrayTesting.Length; i++)
{
string item = arrayTesting[i];
sb.Append("\"");
sb.Append(item);
if (i == arrayTesting.Length - 1)
{
sb.Append("\"]");
}
else
sb.Append("\",");
}
Console.WriteLine(sb);
Instead of converting it to an array, you could use a linq operator on the list to write all the values into a string.
string temp = "";
testing.ForEach(x => temp += x + ", ");
This will leave you with a single string with each value in the list separated by a comma.

I want substring from set of string after a pattern exist in c#

I have 3 string ---
m60_CLDdet2_LOSS2CLF_060520469434_R0RKE_52_GU
m60_CLDdet2_LOSS2CLF_060520469434_R10KE_52_TCRER
m60_CLDdet2_LOSS2CLF_060520469434_R0HKE_52_NT
and I want R0RKE_52_GU, R10KE_52_TCRER,R0HKE_52_NT.
Note: m60_CLDdet2_LOSS2CLF_060520469434 is varying so I want to find substring if R0RKE or R10KE or R0HKE exists
I would suggest using a Regular expression for this, it is much more versatile for pattern matching.
var matches = System.Text.RegularExpressions.Regex.Matches(text, #"(R0RKE|R10KE|R0HKE).*");
I want to find substring if R0RKE or R10KE or R0HKE exists
This LINQ query returns the desired result:
var strings=new[]{"m60_CLDdet2_LOSS2CLF_060520469434_R0RKE_52_GU","m60_CLDdet2_LOSS2CLF_060520469434_R10KE_52_TCRER","m60_CLDdet2_LOSS2CLF_060520469434_R0HKE_52_NT"};
string[] starts = { "R0RKE", "R10KE", "R0HKE" };
var result = strings
.Select(str => new { str, match = starts.FirstOrDefault(s => str.IndexOf("_" + s) >= 0)})
.Where(x => x.match != null)
.Select(x => x.str.Substring(x.str.IndexOf(x.match)));
Console.Write(String.Join(",", result)); // R0RKE_52_GU,R10KE_52_TCRER,R0HKE_52_NT
I write it into static method:
private static string TakeIt(string inputString)
{
if (!Regex.IsMatch(inputString, "(R0RKE|R10KE|R0HKE)"))
{
return string.Empty;
}
var regex = new Regex(#"_");
var occurances = regex.Matches(inputString);
var index = occurances[3].Index + 1;
return inputString.Substring(index, inputString.Length - index);
}
void Main()
{
var string1 = "m60_CLDdet2_LOSS2CLF_060520469434_R0RKE_52_GU";
var string2 = "m60_CLDdet2_LOSS2CLF_060520469434_R10KE_52_TCRER";
var string3 = "m60_CLDdet2_LOSS2CLF_060520469434_R0HKE_52_NT";
var string4 = "m60_CLDdet2_LOSS2CLF_060520469434_hhhhh";
Console.WriteLine(TakeIt(string1));
Console.WriteLine(TakeIt(string2));
Console.WriteLine(TakeIt(string3));
Console.WriteLine(TakeIt(string4));
}
Hope this help.
Update: added .Any - it simplifies the code and it's just as same efficient.
If you just need to check for three strings inside string array you can do :
static string[] GetStrings(string[] dirty, string[] lookUpValues)
{
List<string> result = new List<string>();
for (int i = 0; i < dirty.Length; i++) if (lookUpValues.Any(dirty[i].Contains)) result.Add(dirty[i]);
return result.ToArray();
}
Usage: string[] result = GetStrings(dirty, new[] {"R0RKE", "R10KE", "R0HKE"});
Also you can use LINQ query and Regex.Matches as others advised.

How to get string after specific string?

How to get string after text "playlist:" ?
var YT= "tag:youtube.com,2008:user:hollywoodlife09:playlist:PLDovhwKa3P88MwGzYxMDMfiAiiEWxAJYj" ;
What I did :
string[] s = YT.Split(':');
But it will give me array i.e s[0],s[1] ... and I am searching for something which can give result after specific text.
I want string after "playlist:", I know it may be easy with Regex,but currently I don't have any idea for Regex..
You can use Substring method
var output = inputString.SubString(inputString.LastIndexOf("playlist") + 8);
Or in this case it can be done using Last method via Split:
string output = YT.Split(':').Last();
Using regex replace, remove everything before the :playlist: with empty string.
string playlist = Regex.Replace(YT, ".*:playlist:", "");
more reusably,
static IEnumerable<KeyValuePair<string, string>> SplitPairs(
this string source,
params char[] seperators)
{
var values = source.Split(seperators);
for(var i = 0; i < values.Length; i += 2)
{
yield return new KeyValuePair<string, string>(
values[i],
values[i + 1]);
}
}
so you could do,
var yTlookup = YT.SplitPairs(':').ToDictionary(p => p.Key, p => p.Value);
var playList = yTLookup["playlist"];
or if you don't want an extension,
var segments = YS.Split(new[] { ':' });
var ySlookup = Enumerable.Range(0, segemnts.Length / 2)
.ToDictionary(i => segments[i * 2], i => segments[(i * 2) + 1]);
so you can do,
var playlist = ysLookup["playlist"];
either approach pays off as soon as you want another value from the sequence.
The regex is .+playlist:([^:])

get values from array and add into one string

Object Book has Author which has property Name of type string.
I want to iterate trough all Authors and add it's Name string to the one string (not array) separated by comma, so this string should be at the as
string authorNames = "Author One, Author two, Author three";
string authorNames = string.Empty;
foreach(string item in book.Authors)
{
string fetch = item.Name;
??
}
You can use the string.Join function with LINQ
string authorNames = string.Join(", ", book.Authors.Select(a => a.Name));
You can use
string authors = String.Join(", ", book.Authors.Select(a => a.Name));
LINQ is the way to go in C#, but for explanatory purposes here is how you could code it explicitly:
string authorNames = string.Empty;
for(int i = 0; i < book.Authors.Count(); i++)
{
if(i > 0)
authorNames += ", ";
authorNames += book.Authors[i].Name;
}
You could also loop through them all, and append them to authorNames and add a comma in the end, and when it's done simply trim of the last comma.
string authorNames = string.Empty;
foreach(string author in book.Authors)
{
string authorNames += author.Name + ", ";
}
authorNames.TrimEnd(',');
Using LinQ, there are plenty of ways to merge multiple string into one string.
book.Authors.Select(x => x.Name).Aggregate((x, y) => x + ", " + y);
To anwsers James' comment
[TestMethod]
public void JoinStringsViaAggregate()
{
var mystrings = new[] {"Alpha", "Beta", "Gamma"};
var result = mystrings.Aggregate((x, y) => x + ", " + y);
Assert.AreEqual("Alpha, Beta, Gamma", result);
}

How to remove comma separated value from a string?

I want to remove a comma separated value from the string..
suppose I have a string like this
string x="r, v, l, m"
and i want to remove r from the above string, and reform the string like this
string x="v, l, m"
from the above string i want to remove any value that my logic throw and reform the string.
it should remove the value and comma next to it and reform the string...
The below is specific to my code..
I want to remove any value that I get from the logic, I want to remove it and comma next to it and reform the string with no empty space on the deleted item.. How can I achieve this?
offIdColl = my_Order.CustomOfferAppliedonOrder.TrimEnd(',');
if (offIdColl.Split(',').Contains(OfferID.ToString()))
{
// here i want to perform that operation.
}
Tombala, i applied it like this but it doesn't work..it returns true
if (!string.IsNullOrEmpty(my_Order.CustomOfferAppliedonOrder))
{
offIdColl = my_Order.CustomOfferAppliedonOrder.TrimEnd(',');
if (offIdColl.Split(',').Contains(OfferID.ToString()))
{
string x = string.Join(",", offIdColl.Split(new char[] { ',' },
StringSplitOptions.RemoveEmptyEntries).ToList().Remove(OfferID.ToString()));
}
}
}
Just do something like:
List<String> Items = x.Split(",").Select(i => i.Trim()).Where(i => i != string.Empty).ToList(); //Split them all and remove spaces
Items.Remove("v"); //or whichever you want
string NewX = String.Join(", ", Items.ToArray());
Something like this?
string input = "r,v,l,m";
string output = String.Join(",", input.Split(',').Where(YourLogic));
bool YourLogic(string x)
{
return true;
}
var l = x.Split(new char[] { ',' }, StringSplitOptions.RemoveEmptyEntries).ToList();
l.Remove(OfferID.ToString());
x = string.Join(",", l);
Edit: Sorry, you're right. Remove doesn't return the original list. You need multiple statements. But you don't need to trim the end "," implicitly. You can remove that statement from your code as well as the check to see if the item is there or not. The Remove will take it out if it was found or simply return false if it was not found. You don't have to check existence. So remove the TrimEnd from the first and get rid of the second line below:
offIdColl = my_Order.CustomOfferAppliedonOrder; //.TrimEnd(',');
//if (offIdColl.Split(',').Contains(OfferID.ToString()))
Not quite sure if this is what you mean, but this seems simplest and most readable:
string x = "r, v, l, m";
string valueToRemove = "r";
var result = string.Join(", ", from v in x.Split(',')
where v.Trim() != valueToRemove
select v);
Edit: like Bob Sammers pointed out, this only works in .NET 4 and up.
String input = "r, v, l, m, ";
string itemToReplace = "v, ";
string output = input.Replace(itemToReplace, string.Empty)
public void string Remove(string allStuff, string whatToRemove)
{
StringBuilder returnString = new StringBuilder();
string[] arr = allStuff.Split('');
foreach (var item in arr){
if(!item.Equals(whatToRemove)){
returnString.Append(item);
returnString.Append(", ");
}
}
return returnString.ToString();
}
So you want to delete an item (or replace it with a nother value) and join the string again with comma without space?
string x = "r, v, l, m,";
string value = "v";
string[] allVals = x.TrimEnd(',').Split(new []{','}, StringSplitOptions.RemoveEmptyEntries);
// remove all values:
x = string.Join(",", allVals.Where(v => v.Trim() != value));
// or replace these values
x = string.Join(",", allVals.Select(v => v.Trim() == value ? "new value" : v));
// If you want to remove ALL occurences of the item, say "a" you can use
String data = "a, b, c, d, a, e, f, q, a";
StringBuilder Sb = new StringBuilder();
foreach (String item in data.Split(',')) {
if (!item.Trim().Equals("a", StringComparison.Ordinal)) {
if (Sb.Length > 0)
Sb.Append(',');
Sb.Append(item);
}
}
data = Sb.ToString();
Its just single line of code in many ways, two of them are below:
string x = "r,v,l,m";
string NewX = String.Join(",", from i in x.Split(',') where i != String.Empty && i != "v" select i);
OR
string NewX = String.Join(",", x.Split(',').Select(i => i.Trim()).Where(i => i != String.Empty && i != "v"));
Not going about this right. Do you need to keep the string? I doubt you do. Just use a list instead. Can you have duplicates? If not:
offIdColl = my_Order.CustomOfferAppliedonOrder.TrimEnd(',').Split(',');
if (offIdColl.Contains(OfferID.ToString()))
{
offIdColl.Remove(OfferID.ToString());
}

Categories