6

I have the following list

List<string> listString = new List<string>() { "UserId", "VesselId", "AccountId", "VesselId" };

I would like to use a Linq operator which removes only the first occurrence of VesselId.

Patrice Gahide
  • 3,644
  • 1
  • 27
  • 37
DenisSuarez
  • 81
  • 1
  • 1
  • 4

5 Answers5

6

you can not change the original collection with LINQ, so the closest thing would be:

var index = listString.IndexOf("VesselId");
if(index>-1)
   listString.RemoveAt(index);

EDIT 1:

According to research done by Igor Mesaros, I ended up implementing the logic which resides in the List.Remove method, so an even simpler solution would be:

listString.Remove("VesselId");
Eyal Perry
  • 2,255
  • 18
  • 26
4

If you have a simple list of strings or some other primitive type, then you can just call:

listString.Remove("VesselId");

as mentioned by @Eyal Perry

If you have a huge none primitive list, this is the most efficient

class MyClass
{
   string Name {get; set;}
}

var listString = new List<MyClass>() {/* Fill in with Data */};
var match = listString.FirstOrDefault(x => x.Name == "VesselId");

if(match != null)
     listString.Remove(match);
Igor Meszaros
  • 2,081
  • 2
  • 22
  • 46
  • The first and second lines of code are completely redundant. – Eyal Perry Jun 10 '16 at 12:37
  • What if the list is not a list of string, but generic? The op wanted a linq query. So I thought the string list is just an example... but fair point – Igor Meszaros Jun 10 '16 at 12:41
  • then the class author needs to override the Equals method, since I bet that Remove invokes it.. Also, note that the author of the question does not know much about LINQ, which does not change the original collection.. He probably meant that he wanted to use some kind of shorthand, without iterating the collection himself. http://referencesource.microsoft.com/#mscorlib/system/collections/generic/list.cs,db8cdd552a0bb10c – Eyal Perry Jun 10 '16 at 12:48
  • Only when using the explicit implementation of the Remove function, the implicit implementation doesn't require the class of Type T to inherit IComparable. Yea... I didn't realize someone was asking how to use .Remove – Igor Meszaros Jun 10 '16 at 12:55
  • If by implicit you mean the Enumerable one, I believe the implicit implementation implicitly requires that the interface is implemented, unless you invoke an overload which receives a comparer instance.. Remove() by itself is quite good and an even better solution than what I suggested, If you believe its documentation. I am a bit paranoid since I have found some discrepancies a couple of times, therefore I suggested my solution which assures the requested behavior. – Eyal Perry Jun 10 '16 at 12:59
  • 1
    // Removes the element at the given index. The size of the list is // decreased by one. // public bool Remove(T item) { int index = IndexOf(item); if (index >= 0) { RemoveAt(index); return true; } return false; } This doesn't care weather its IComparable or not.. FirstOrDefault will return the exact same instance that needs to be removed, it doesn't need to compare itself! – Igor Meszaros Jun 10 '16 at 13:04
  • *Bows down and removes hat* :) Well done sir (not cynical, just humbled) – Eyal Perry Jun 10 '16 at 13:06
  • I still do not see the necessity for the FirstOrDefault.. you do know that string is just a class, exactly like any other class, and Remove will work, depending of how the Equals method of the object evaluates? please consider this.. – Eyal Perry Jun 10 '16 at 13:34
1

If what you are looking to do is get a distinct list then you have an extension method for that listString.Distinct()

Gilad Green
  • 36,708
  • 7
  • 61
  • 95
  • the list is too long it will take a lot of time. Is there shorter way ? – DenisSuarez Jun 10 '16 at 12:13
  • @DenisSuarez - Where do you get the data from? Do you control the inserting to it or do you get it from somewhere. If you put the elements in then you can change from a List to a HashSet and then first look if it already exists in the collection. (HashSet because it'll be in o(1) instead of o(n) – Gilad Green Jun 10 '16 at 12:14
  • 1
    @GiladGreen Distinct will surely go through the entire list, and is overkill for the specified use case, which is to remove the first encountered item, which could potentially enumerate over less than the entire thing, let alone an IEnumerable which infinitely yields items. – Eyal Perry Jun 10 '16 at 12:25
  • @Eyal Perry - I agree with you. That is why I asked about where he gets the information form - it is specifically the "VesselID" or any dups – Gilad Green Jun 10 '16 at 12:27
  • @GiladGreen :) Also, for future googlers.. Distinct will also allocate a new collection, while the question's author clearly wishes the item to be removed from an existing collection. – Eyal Perry Jun 10 '16 at 13:05
0

If you absolutely MUST use LINQ, you can use it to find the first instance of "VesselId" inside the Remove() method, like so:

listString.Remove((from a in listString
                   where a == "VesselId"
                   select a).First());
-1
listString = listString.Union(new List<string>()).ToList();

OR

List<string> CopyString = new List<string>();
            CopyString.AddRange(listString);
            foreach (var item in CopyString)
            {
                var index = CopyString.IndexOf(item);
                if (index >= 0 && listString.Count(cnt => cnt == item) > 1)
                    listString.RemoveAt(index);
            }
Alper Şaldırak
  • 1,034
  • 8
  • 10