For whatever reason, you have a list of items and it has values you wish to discard. I'm going to use strings for my example, but you can use any comparable type. I'm going to show you a good, better, best on doing so.

If you're here because you're looking for an array based solution, I recommend you add using System.Collections.Generic; and push that array into a list first with List<string> removalList = new List<string>(myStringArray); and if you really need it to be an array at the end (perhaps legacy enterprise libraries), follow up with: myStringArray = removalList.ToArray();

First, a relatively simple removal method…

using System.Collections.Generic;
using System.Diagnostics;
using System.Text.RegularExpressions;

List<string> test = new List<string>(10000);
string[] letters = Regex.Split("abcdefghijklmnopqrstuvwxyz", string.Empty);

for (int x = 0; x < 10000; ++x) {
    test.Add(letters[x % letters.Length]);
}

Stopwatch sw = new Stopwatch();
sw.Start();
foreach (string y in letters) {
    while (test.Contains(y)) {
        test.Remove(y);
    }
    Console.WriteLine("Removed " + y + ", " + test.Count + " remaining, " + sw.ElapsedMilliseconds + " elapsed.");
}
sw.Stop();
Console.WriteLine("Timer: " + sw.ElapsedMilliseconds);

Since .Remove(value) only removes the first value we have to keep checking if we got them all. Also, I could have wrapped the while in a check to see if Y was null or empty, but in a real-world setting, you might want to be removing exactly those values and will likely have a very specific list of removals to make vs stripping out everything as I'm doing for demonstration purposes.

Now, a better method…

using System.Collections.Generic;
using System.Diagnostics;
using System.Text.RegularExpressions;

List<string> test = new List<string>(10000);
string[] letters = Regex.Split("abcdefghijklmnopqrstuvwxyz", string.Empty);

for (int x = 0; x < 10000; ++x) {
    test.Add(letters[x % letters.Length]);
}

Stopwatch sw = new Stopwatch();
sw.Start();
foreach (string y in letters) {
    for (int z = test.Count - 1; z > -1; --z) {
        if (test[z].Equals(y)) {
            test.RemoveAt(z);
        }
    }
    Console.WriteLine("Removed " + y + ", " + test.Count + " remaining, " + sw.ElapsedMilliseconds + " elapsed.");
}
sw.Stop();
Console.WriteLine("Timer: " + sw.ElapsedMilliseconds);

//--------


Big speed improvement as we step down the list (approximately 40× faster in my tests). We go backwards so we don't have to account for removed index values as we shorten the list. Once an index position is evaluated for removal we're done with it. Otherwise we'd have to keep rechecking the current index value to see if it also needed removed before moving on, plus our upper index limit would have to be reevaluated at each increment of the counter instead of comparing to a constant.

This must be a pretty common task because Microsoft added a RemoveAll() function to lists, but rather than try to make it handle multiple types, you have to create a function called a predicate that returns true for removal of an entry or false to not remove. For a relatively simple comparison check, an anonymous lambda function (value => function) does nicely…

using System.Collections.Generic;
using System.Diagnostics;
using System.Text.RegularExpressions;

List<string> test = new List<string>(10000);
string[] letters = Regex.Split("abcdefghijklmnopqrstuvwxyz", string.Empty);

for (int x = 0; x < 10000; ++x) {
    test.Add(letters[x % letters.Length]);
}

Stopwatch sw = new Stopwatch();
sw.Start();
foreach (string y in letters) {
    test.RemoveAll(z => z.Equals(y));
    Console.WriteLine("Removed " + y + ", " + test.Count + " remaining, " + sw.ElapsedMilliseconds + " elapsed.");
}
sw.Stop();
Console.WriteLine("Timer: " + sw.ElapsedMilliseconds);

//--------


Now we're talking. I was getting an 8× improvement over the seconds method, and 300× better than the first.