5

I'm trying to remove an element/item/entry from a split string.

Let's say I got the string [string_] as follows:

string string_ = "one;two;three;four;five;six";

Then I split this string to get each, let's say, item:

string[] item = (string_.Split(";"));

I have no informations other than from variables. Depending on the user choice, I can get an item value and index.

Let's say that for this example, the user chose "four" which is the index "3".

How can I make my string look like the index 3 have been deleted, as string_ would be equal to the following:

"one;two;three;five;six"

I've tried multiple things and it seems like the only solution is to go through a char method.

Is that true or did I miss something?


EDIT to suggested already_posted_answer : Not quite the same question as my ITEM could be placed anywhere in my splitted string depending on the user selection.

Bo. Ga.
  • 138
  • 1
  • 4
  • 12

5 Answers5

10

First of all you need to write better variable names, string_ is a horrible name. Even something like "input" is way better.

string input = "one;two;three;four;five;six";

Next, you are on the right track by using Split(). This will return an array of string:

string[] splitInput = input.Split(";");

The resulting string array will look like this:

//string[0] = one
//string[1] = two
//string[2] = three
//string[3] = four
//string[4] = five
//string[5] = six

Removing with known index

If you want to remove a specific element from the array, you could make the result of Split() a List<T> by using ToList() instead and utilize the RemoveAt() method of the resulting List<T>:

List<string> splitList = input.Split(';').ToList();
splitList.RemoveAt(3);

//Re-create the string
string outputString = string.Join(";", splitList);
//output is: "one;two;three;five;six"

Remove all strings that match an input

If you need to remove items from the list without knowing their index but knowing the actual string, you can use LINQ's Where() to filter out the matching items:

//Get the input from the user somehow
string userInput = Console.ReadLine();
IEnumerable<string> filteredList = input.Split(';')
                                      .Where(x => string.Compare(x, userInput, true) != 0);

//Re-create the string
string outputString = string.Join(";", filteredList);

I made a fiddle to demonstrate both methods here

maccettura
  • 10,514
  • 3
  • 28
  • 35
  • You are awsome. Now i realise that i was doing my tests with string or int but i completly forgot about that neutral "var". Thank you so much. <3 – Bo. Ga. Feb 16 '18 at 20:31
  • Given "ToList()" call, this is not the best choice in terms of memory. – Yury Schkatula Feb 16 '18 at 20:35
  • @YurySchkatula preemptive optimization is a bad idea. The ToList is needed to use `RemoveAt()` – maccettura Feb 16 '18 at 20:36
  • @maccettura, I understand your approach. Same time, at this case it is just poisoning the CPU cache and GC, and gives a bad habit for the topic starter. – Yury Schkatula Feb 16 '18 at 20:42
  • 1
    @Yury If you are concerned about squeezing Performance Out of the cpu, you are in a totally wrong world. Try Rust or C – Mightee Feb 16 '18 at 21:00
  • 1
    @Mightee, C# gives you a bigger hammer. So, misusing it would create much more performance penalty than misuse of Rust or C. Despite you have GC in C#, you MUST understand how it's working, to not seriously interfere with it. Really. – Yury Schkatula Feb 16 '18 at 21:27
1

You can convert an array of string to list by following:

var list = new List<string>(item);

Once the list is created, you can easily remove an element:

var index = list.IndexOf("four");
list.RemoveAt(index);

Join the string back:

var result = String.Join(";", list.ToArray());

Result:

enter image description here

FaizanHussainRabbani
  • 3,256
  • 3
  • 26
  • 46
0

You can convert your string array into a List<string>, and since you have the index of the item to be removed, you can remove the item using RemoveAt, then join the items back into one string.

Here's a complete console application example:

static void Main(string[] args)
{
    string string_ = "one;two;three;four;five;six";
    string[] items = (string_.Split(';'));

    Console.WriteLine("Please select an item to remove:");
    for (int i = 0;i<items.Length;i++)
    {
        Console.WriteLine(string.Format("{0}- {1}", (i + 1).ToString(), items[i]));
    }
    int num = 0;
    int.TryParse(Console.ReadLine(), out num);
    if (num > 0 && num <= items.Length)
    {
        List<string> itemsList = items.ToList();
        itemsList.RemoveAt(num - 1);
        string newString = string.Join(";", itemsList);
        Console.WriteLine(string.Format("The new string is: {0}", newString));
    }
    else
    {
        Console.WriteLine("Invalid number!");
    }
    Console.ReadLine();
}

Hope that helps.

0

We can employ LINQ. Initial plan is to split the string, then create a union of two enumerables: before and after the item. Something like this:

    // preconditions
    const int idx = 3;
    string string_ = "one;two;three;four;five;six";

    // actual transformation
    string[] item = (string_.Split(';'));
    var iterator = item.Take(idx).Concat(item.Skip(idx + 1));

    // output the results
    var result = string.Join(";", iterator);
    Console.Write(result);
Yury Schkatula
  • 5,291
  • 2
  • 18
  • 42
  • This works like a charm as well. Thanks for your help. Care to explain how your solution is better for memory ? I'm new to memory optimisation and maccettura's solution is easier (at my level) for me to understand. – Bo. Ga. Feb 16 '18 at 20:54
  • 1
    This solution is incorrect if there can be duplicates in the list. Why "union" and not "concat"? – Eric Lippert Feb 16 '18 at 21:27
  • 1
    Also, you are iterating the sequence twice, unnecessarily. You would do far better to write your own helper function: `public static IEnumerable SkipOver(this IEnumerable items, int index) => items.Where((dummy, i) => i != index)` and then just say `string.Join(";", items.SkipOver(index))` Now you are (1) iterating the sequence only once, and (2) you've built a helper method that might be more generally useful, that is self-describing. – Eric Lippert Feb 16 '18 at 21:30
  • @EricLippert, oh! You're quite right, I forgot about distinct nature of Union(). Going to amend my answer. – Yury Schkatula Feb 16 '18 at 21:30
  • @Bo.Ga., that solution creates too much temp instances that could be used for nothing. Just imagine you visited a grocery shop, then returned home with full car of food, then dumped out to waste bin everything but small cake. – Yury Schkatula Feb 16 '18 at 21:38
  • @YurySchkatula The return type of `string.Split()` is already an array. Calling `.ToList()` from that is about as cheap of a conversion as you can get. The resulting overhead in memory is just a few bytes (~40 to be more specific). See the analysis [here](https://dotnetfiddle.net/lk5EHT) – maccettura Feb 16 '18 at 22:00
  • @Bo.Ga. This solution would not have any noticeable improvement over mine. See my comments, my basic [analysis](https://dotnetfiddle.net/lk5EHT) and read [this answer](https://stackoverflow.com/a/15517544/2457029). – maccettura Feb 16 '18 at 22:04
-2

Would this work for you?

If you create a new string like this, then replace the value of string_ with the value of the new string.

string string_ = "one;two;three;four;five;six";
string newstring = string_.Replace("four", "");
string_ = newstring.Replace(";;", ";");
nocturns2
  • 663
  • 10
  • 17