How to remove comma separated value from a string? - c#

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());
}

Related

Linq lambda foreach

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);

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);
}

Replace every other of a certain char in a string

I have searched a lot to find a solution to this, but could not find anything. I do however suspect that it is because I don't know what to search for.
First, I have a string that I convert to an array. The string will be formatted like so:
"99.28099822998047,68.375 118.30699729919434,57.625 126.49999713897705,37.875 113.94499683380127,11.048999786376953 96.00499725341797,8.5"
I create the array with the following code:
public static Array StringToArray(string String)
{
var list = new List<string>();
string[] Coords = String.Split(' ', ',');
foreach (string Coord in Coords)
{
list.Add(Coord);
}
var array = list.ToArray();
return array;
}
Now my problem is; I am trying to find a way to convert it back into a string, with the same formatting. So, I could create a string simply using:
public static String ArrayToString(Array array)
{
string String = string.Join(",", array);
return String;
}
and then hopefully replace every 2nd "," with a space (" "). Is this possible? Or are there a whole other way you would do this?
Thank you in advance! I hope my question makes sense.
There is no built-in way of doing what you need. However, it's pretty trivial to achieve what it is you need e.g.
public static string[] StringToArray(string str)
{
return str.Replace(" ", ",").Split(',');
}
public static string ArrayToString(string[] array)
{
StringBuilder sb = new StringBuilder();
for (int i = 0; i <= array.Length-1; i++)
{
sb.AppendFormat(i % 2 != 0 ? "{0} " : "{0},", array[i]);
}
return sb.ToString();
}
If those are pairs of coordinates, you can start by parsing them like pairs, not like separate numbers:
public static IEnumerable<string[]> ParseCoordinates(string input)
{
return input.Split(' ').Select(vector => vector.Split(','));
}
It is easier then to reconstruct the original string:
public static string PrintCoordinates(IEnumerable<string[]> coords)
{
return String.Join(" ", coords.Select(vector => String.Join(",", vector)));
}
But if you absolutely need to have your data in a flat structure like array, it is then possible to convert it to a more structured format:
public static IEnumerable<string[]> Pairwise(string[] coords)
{
coords.Zip(coords.Skip(1), (coord1, coord2) => new[] { coord1, coord2 });
}
You then can use this method in conjunction with PrintCoordinates to reconstruct your initial string.
Here is a route to do it. I don't think other solutions were removing last comma or space. I also include a test.
public static String ArrayToString(Array array)
{
var useComma = true;
var stringBuilder = new StringBuilder();
foreach (var value in array)
{
if (useComma)
{
stringBuilder.AppendFormat("{0}{1}", value, ",");
}
else
{
stringBuilder.AppendFormat("{0}{1}", value, " ");
}
useComma = !useComma;
}
// Remove last space or comma
stringBuilder.Length = stringBuilder.Length - 1;
return stringBuilder.ToString();
}
[TestMethod]
public void ArrayToStringTest()
{
var expectedStringValue =
"99.28099822998047,68.375 118.30699729919434,57.625 126.49999713897705,37.875 113.94499683380127,11.048999786376953 96.00499725341797,8.5";
var array = new[]
{
"99.28099822998047",
"68.375",
"118.30699729919434",
"57.625",
"126.49999713897705",
"37.875",
"113.94499683380127",
"11.048999786376953",
"96.00499725341797",
"8.5",
};
var actualStringValue = ArrayToString(array);
Assert.AreEqual(expectedStringValue, actualStringValue);
}
Another way of doing it:
string inputString = "1.11,11.3 2.22,12.4 2.55,12.8";
List<string[]> splitted = inputString.Split(' ').Select(a => a.Split(',')).ToList();
string joined = string.Join(" ", splitted.Select(a => string.Join(",",a)).ToArray());
"splitted" list will look like this:
1.11 11.3
2.22 12.4
2.55 12.8
"joined" string is the same as "inputString"
Here's another approach to this problem.
public static string ArrayToString(string[] array)
{
Debug.Assert(array.Length % 2 == 0, "Array is not dividable by two.");
// Group all coordinates as pairs of two.
int index = 0;
var coordinates = from item in array
group item by index++ / 2
into pair
select pair;
// Format each coordinate pair with a comma.
var formattedCoordinates = coordinates.Select(i => string.Join(",", i));
// Now concatinate all the pairs with a space.
return string.Join(" ", formattedCoordinates);
}
And a simple demonstration:
public static void A_Simple_Test()
{
string expected = "1,2 3,4";
string[] array = new string[] { "1", "2", "3", "4" };
Debug.Assert(expected == ArrayToString(array));
}

How to retrieve a substring based on a first list match

In a string I need to recover a 7 char substring based on the first match from any item in a list. If a match is not made it should return an empty string.
I have the following code:
List<string> myList = new List<string>()
{
"TNCO",
"TNCB",
"TNIT"
};
string sample = "TNSD102, WHRK301, TNIT301, YTRE234";
//doesn't give an index
bool anyfound = myList.Any(w => sample.Contains(w));
//code that needs replacing
string code = sample.Substring(sample.IndexOf("TNC"), 7);
if (code == "")
{
code = sample.Substring(sample.IndexOf("TNIT"), 7);
}
The list is never likely to be more than 35-40 items and the strings < 50 chars.
Anyone able to point me in the right direction?
string val1 = (sample.Split(',').FirstOrDefault(w => myList.Any(m => w.Contains(m))) ?? string.Empty).Trim();
This gives you an IEnumerable of all matches:
var matches = from code in sample.Split(',')
from w in myList
where code.Trim().StartsWith(w)
select code;
To get the first value use FirstOrDefault. Then use the coalesce operator ?? to return an empty string if there was no match.
string firstMatch = (matches.FirstOrDefault() ?? "").Trim();
With data sets this small, you can simply split the string and search for the first match:
// split the sample string into separate entries
var entries = sample.Split(new char[] {',', ' '},
StringSplitOptions.RemoveEmptyEntries);
// find the first entry starting with any allowed prefix
var firstMatch = entries.FirstOrDefault (
e => myList.Any (l => e.StartsWith(l)));
// FirstOrDefault returns null if there are no matches
if (firstMatch == null)
Console.WriteLine("No match!");
else
Console.WriteLine(firstMatch);
Example output (DEMO):
TNIT301
List<string> myList = new List<string> { "TNCO", "TNCB", "TNIT" };
string sample = "TNSD102, WHRK301, TNIT301, YTRE234";
string[] sampleItems = sample.Split(new[] { ',', ' ' }, StringSplitOptions.RemoveEmptyEntries);
var results = myList
.Select(prefix => sampleItems
.FirstOrDefault(item => item.StartsWith(prefix)) ?? "");
Running this code here returns an Index of 2 based on what you are trying to find.
int keyIndex = myList.FindIndex(w => samples.Contains(w));
TNIT301 this is the indexed string value
you could also do the following to return the string value in index position of keyIndex variable value.
var subStrValue = samples.Split(',')[keyIndex];

Extracting parts of a string c#

In C# what would be the best way of splitting this sort of string?
%%x%%a,b,c,d
So that I end up with the value between the %% AND another variable containing everything right of the second %%
i.e. var x = "x"; var y = "a,b,c,d"
Where a,b,c.. could be an infinite comma seperated list. I need to extract the list and the value between the two double-percentage signs.
(To combat the infinite part, I thought perhaps seperating the string out to: %%x%% and a,b,c,d. At this point I can just use something like this to get X.
var tag = "%%";
var startTag = tag;
int startIndex = s.IndexOf(startTag) + startTag.Length;
int endIndex = s.IndexOf(tag, startIndex);
return s.Substring(startIndex, endIndex - startIndex);
Would the best approach be to use regex or use lots of indexOf and substring to do the extracting based on te static %% characters?
Given that what you want is "x,a,b,c,d" the Split() function is actually pretty powerful and regex would be overkill for this.
Here's an example:
string test = "%%x%%a,b,c,d";
string[] result = test.Split(new char[] { '%', ',' }, StringSplitOptions.RemoveEmptyEntries);
foreach (string s in result) {
Console.WriteLine(s);
}
Basicly we ask it to split by both '%' and ',' and ignore empty results (eg. the result between "%%"). Here's the result:
x
a
b
c
d
To Extract X:
If %% is always at the start then;
string s = "%%x%%a,b,c,d,h";
s = s.Substring(2,s.LastIndexOf("%%")-2);
//Console.WriteLine(s);
Else;
string s = "v,u,m,n,%%x%%a,b,c,d,h";
s = s.Substring(s.IndexOf("%%")+2,s.LastIndexOf("%%")-s.IndexOf("%%")-2);
//Console.WriteLine(s);
If you need to get them all at once then use this;
string s = "m,n,%%x%%a,b,c,d";
var myList = s.ToArray()
.Where(c=> (c != '%' && c!=','))
.Select(c=>c).ToList();
This'll let you do it all in one go:
string pattern = "^%%(.+?)%%(?:(.+?)(?:,|$))*$";
string input = "%%x%%a,b,c,d";
Match match = Regex.Match(input, pattern);
if (match.Success)
{
// "x"
string first = match.Groups[1].Value;
// { "a", "b", "c", "d" }
string[] repeated = match.Groups[2].Captures.Cast<Capture>()
.Select(c => c.Value).ToArray();
}
You can use the char.IsLetter to get all the list of letter
string test = "%%x%%a,b,c,d";
var l = test.Where(c => char.IsLetter(c)).ToArray();
var output = string.Join(", ", l.OrderBy(c => c));
Since you want the value between the %% and everything after in separate variables and you don't need to parse the CSV, I think a RegEx solution would be your best choice.
var inputString = #"%%x%%a,b,c,d";
var regExPattern = #"^%%(?<x>.+)%%(?<csv>.+)$";
var match = Regex.Match(inputString, regExPattern);
foreach (var item in match.Groups)
{
Console.WriteLine(item);
}
The pattern has 2 named groups called x and csv, so rather than just looping, you can easily reference them by name and assign them to values:
var x = match.Groups["x"];
var y = match.Groups["csv"];

Categories