Trying to figure out how to add a string character to a string array using .Where

Below is my string array. I got this .Where code online and I found it really interesting and I tried modifying it to make it add a character instead of removing a character. However I keep getting the "Method Name Expected error under the 'indexremove' variable on the last line. Is there any solution to this problem? Or is my modification not able to work?

string[] TestArray = {"a", "b", "c", "d", "e"};

int indexremove = 0;      // for removing the character in the 1st position; a.

TestArray = TestArray.Where((source, index) => index != indexremove).ToArray(); //source, index points to the array's character collection, and index != indexremove causes A to be removed from the index of the array. Then it is converted to an array.

foreach (string value in TestArray) {Console.WriteLine(value); //displays output of new array without "a" }

string indextoadd = "a"; //trying to re-add the character back in to the array


TestArray = TestArray.Where((source, index) => index + indexremove(indextoadd)).ToArray(); //Method Name Expected on indexremove

Solution 1:

Where doesn't work like this. It's a filtering device so it intrinsically cannot be used to extend/add to a list of things. The only thing you can do with a Where is prevent one of the input items being output, if some test returns false

For any given list of items;

string[] testArray = {"a", "b", "c", "d", "e"};

You can write a Where, and pass to the Where a small nugget of code (we tend to refer to it as a lambda) that is like a nameless method. It must accept one or two arguments and it must return a bool. Where will loop over the input list of items, calling the lambda you passed on each one of the items. If the lambda returns true, the inputted item is output. If it returns false, the list item being looped is not output

These are the conceptual equivalents:

//this nice short thing
testArray.Where(s => s.Length == 1);


//is like this longer thing

public bool LengthIs1(string s){
  return s.Length == 1;
}
...
foreach(var s in testArray)
  if(LengthIs1(s))
    output s;    //this is a pretend thing: `output` doesn't exist but it means I don't also have to explain yield return. Just imagine that it sends the value out and carries on looping

Examples

testArray.Where(s => true);        //every item will be output
testArray.Where(s => false);       //no item will be output
testArray.Where(s => s == "a");    //only items equal to "a" will be output 
testArray.Where(s => s.StartsWith("b"));    //only items starting with b will be output 
testArray.Where(s => DateTime.Now.DayOfWeek == DayOfWeek.Tuesday);     //every item will be output if it's Tuesday, otherwise no item will be output

Those are examples that just take one argument s, to the lambda. There is another form, the one you're using, where the lambda can have two parameters - the first parameter is again the item from the array. The second parameter is the index of the item in the array

testArray.Where((s,index) => true);          //every item will be output
testArray.Where((s,index) => index == 0);    //only the first item will be output
testArray.Where((s,index) => index != 1);    //everything apart from the second item will be output
testArray.Where((s,index) => index%2 == 0);  //even indexed items will be output

As you can see there isn't any scope for extending or adding more items. You start with 100 items, you can only output somewhere between 0 and 100 items

In the code you posted the first item is filtered out because the lambda assessed index versus index to remove, and will return true (keep) in all cases where they're not the same, and return false (remove) when they are the same

If you want to output more items you have to use something else, like Concat

new[]{1,2}.Concat(new[]{3,4})

This will output an enumeration of 1,2,3,4

Because Where produces an enumerable thing, and Concat can be called on an enumerable thing and accepts as a parameter another enumerable thing it means we could do something like:

testArray
  .Where((s,index) => index != indextoremove)
  .Concat( 
    testArray.Where((s,index) => index == indextoremove)
  )

The first Where excludes only the indextoremove (it keeps the rest) and the second Where keeps only the indextoremove (it excludes the rest). The Concat would just effectively take the first sequence, where "a" has been excluded and then concatenate on the second sequence where "a" is the only one included. This would essentially move "a" from the start, to the end of the sequence

It's horrifically inefficient, but this example is more about learning


(source, index) => index + indexremove(indextoadd)

This is, alas, flat out a syntax error. You've made indextoadd a string, and index to remove is an int. you can't follow an int variable name with a ( because you cannot execute/call an int. You this also cannot execute an int passing a string to it. As the final nail in the lambda's coffin, it's supposed to return a bool but you've done something approaching a numeric result, if int + int(string) was even possible. In full method terms you've done something like:

public bool AMethod(string source, int index){
  string indextoadd = "a";
  int indexremove = 1;
  return index + indexremove(indextoadd);
}

Which hopefully you can see has a lot of syntax and logical problems..