How to replace list item in best way

C#

C# Problem Overview


if (listofelements.Contains(valueFieldValue.ToString()))
{
    listofelements[listofelements.IndexOf(valueFieldValue.ToString())] = value.ToString();
}

I have replaced like above. Is there any other bestway to place compare than this one?

C# Solutions


Solution 1 - C#

Use Lambda to find the index in the List and use this index to replace the list item.

List<string> listOfStrings = new List<string> { "abc", "123", "ghi" };

int index = listOfStrings.FindIndex(s => s == "123");

if (index != -1)
    listOfStrings[index] =  "def";

Solution 2 - C#

You could make it more readable and more efficient:

string oldValue = valueFieldValue.ToString();
string newValue = value.ToString();
int index = listofelements.IndexOf(oldValue);
if(index != -1)
    listofelements[index] = newValue;

This asks only once for the index. Your approach uses Contains first which needs to loop all items(in the worst case), then you're using IndexOf which needs to enumerate the items again .

Solution 3 - C#

Why not use the extension methods?

Consider the following code:

        var intArray = new int[] { 0, 1, 1, 2, 3, 4 };
        // Replaces the first occurance and returns the index
        var index = intArray.Replace(1, 0);
        // {0, 0, 1, 2, 3, 4}; index=1

        var stringList = new List<string> { "a", "a", "c", "d"};
        stringList.ReplaceAll("a", "b");
        // {"b", "b", "c", "d"};

        var intEnum = intArray.Select(x => x);
        intEnum = intEnum.Replace(0, 1);
        // {0, 0, 1, 2, 3, 4} => {1, 1, 1, 2, 3, 4}
  • No code duplication
  • There is no need to type long linq expressions
  • There is no need for additional usings

The source code:

namespace System.Collections.Generic
{
    public static class Extensions
    {
        public static int Replace<T>(this IList<T> source, T oldValue, T newValue)
        {
            if (source == null)
                throw new ArgumentNullException(nameof(source));

            var index = source.IndexOf(oldValue);
            if (index != -1)
                source[index] = newValue;
            return index;
        }

        public static void ReplaceAll<T>(this IList<T> source, T oldValue, T newValue)
        {
            if (source == null)
                throw new ArgumentNullException(nameof(source));

            int index = -1;
            do
            {
                index = source.IndexOf(oldValue);
                if (index != -1)
                    source[index] = newValue;
            } while (index != -1);
        }


        public static IEnumerable<T> Replace<T>(this IEnumerable<T> source, T oldValue, T newValue)
        {
            if (source == null)
                throw new ArgumentNullException(nameof(source));

            return source.Select(x => EqualityComparer<T>.Default.Equals(x, oldValue) ? newValue : x);
        }
    }
}

The first two methods have been added to change the objects of reference types in place. Of course, you can use just the third method for all types.

P.S. Thanks to mike's observation, I've added the ReplaceAll method.

Solution 4 - C#

You are accessing your list twice to replace one element. I think simple for loop should be enough:

var key = valueFieldValue.ToString();
for (int i = 0; i < listofelements.Count; i++)
{
    if (listofelements[i] == key)
    {
        listofelements[i] = value.ToString();
        break;
    }
}

Solution 5 - C#

Following rokkuchan's answer, just a little upgrade:

List<string> listOfStrings = new List<string> {"abc", "123", "ghi"};

int index = listOfStrings.FindIndex(ind => ind.Equals("123"));
if (index > -1)
    listOfStrings[index] =  "def";

Solution 6 - C#

You can use the next extensions which are based on a predicate condition:

    /// <summary>
    /// Find an index of a first element that satisfies <paramref name="match"/>
    /// </summary>
    /// <typeparam name="T">Type of elements in the source collection</typeparam>
    /// <param name="this">This</param>
    /// <param name="match">Match predicate</param>
    /// <returns>Zero based index of an element. -1 if there is not such matches</returns>
    public static int IndexOf<T>(this IList<T> @this, Predicate<T> match)
    {
        @this.ThrowIfArgumentIsNull();
        match.ThrowIfArgumentIsNull();

        for (int i = 0; i < @this.Count; ++i)
            if (match(@this[i]))
                return i;

        return -1;
    }

    /// <summary>
    /// Replace the first occurance of an oldValue which satisfies the <paramref name="removeByCondition"/> by a newValue
    /// </summary>
    /// <typeparam name="T">Type of elements of a target list</typeparam>
    /// <param name="this">Source collection</param>
    /// <param name="removeByCondition">A condition which decides is a value should be replaced or not</param>
    /// <param name="newValue">A new value instead of replaced</param>
    /// <returns>This</returns>
    public static IList<T> Replace<T>(this IList<T> @this, Predicate<T> replaceByCondition, T newValue)
    {
        @this.ThrowIfArgumentIsNull();
        removeByCondition.ThrowIfArgumentIsNull();

        int index = @this.IndexOf(replaceByCondition);
        if (index != -1)
            @this[index] = newValue;

        return @this;
    }

    /// <summary>
    /// Replace all occurance of values which satisfy the <paramref name="removeByCondition"/> by a newValue
    /// </summary>
    /// <typeparam name="T">Type of elements of a target list</typeparam>
    /// <param name="this">Source collection</param>
    /// <param name="removeByCondition">A condition which decides is a value should be replaced or not</param>
    /// <param name="newValue">A new value instead of replaced</param>
    /// <returns>This</returns>
    public static IList<T> ReplaceAll<T>(this IList<T> @this, Predicate<T> replaceByCondition, T newValue)
    {
        @this.ThrowIfArgumentIsNull();
        removeByCondition.ThrowIfArgumentIsNull();

        for (int i = 0; i < @this.Count; ++i)
            if (replaceByCondition(@this[i]))
                @this[i] = newValue;

        return @this;
    }

Notes:

  • Instead of ThrowIfArgumentIsNull extension, you can use a general approach like:

    if (argName == null) throw new ArgumentNullException(nameof(argName));

So your case with these extensions can be solved as:

string targetString = valueFieldValue.ToString();
listofelements.Replace(x => x.Equals(targetString), value.ToString());

Solution 7 - C#

Use FindIndex and lambda to find and replace your values:

int j = listofelements.FindIndex(i => i.Contains(valueFieldValue.ToString())); //Finds the item index

lstString[j] = lstString[j].Replace(valueFieldValue.ToString(), value.ToString()); //Replaces the item by new value

Solution 8 - C#

You can use lambda expression like this.

int index = listOfElements.FindIndex(item => item.Id == id);  
if (index != -1) 
{
    listOfElements[index] = newValue;
}

Solution 9 - C#

I don't if it is best or not but you can use it also

List<string> data = new List<string>
(new string[]   { "Computer", "A", "B", "Computer", "B", "A" });
int[] indexes = Enumerable.Range(0, data.Count).Where
                 (i => data[i] == "Computer").ToArray();
Array.ForEach(indexes, i => data[i] = "Calculator");

Solution 10 - C#

Or, building on Rusian L.'s suggestion, if the item you're searching for can be in the list more than once::

[Extension()]
public void ReplaceAll<T>(List<T> input, T search, T replace)
{
	int i = 0;
	do {
		i = input.FindIndex(i, s => EqualityComparer<T>.Default.Equals(s, search));

		if (i > -1) {
			FileSystem.input(i) = replace;
			continue;
		}

		break;  
	} while (true);
}

Solution 11 - C#

i find best for do it fast and simple

  1. find ur item in list

     var d = Details.Where(x => x.ProductID == selectedProduct.ID).SingleOrDefault();
    
  2. make clone from current

     OrderDetail dd = d;
    
  3. Update ur clone

     dd.Quantity++;
    
  4. find index in list

     int idx = Details.IndexOf(d);
    
  5. remove founded item in (1)

       Details.Remove(d);
    
  6. insert

      if (idx > -1)
           Details.Insert(idx, dd);
       else
           Details.Insert(Details.Count, dd);
    

Solution 12 - C#

//with multiple replacements - NOT USING FOREACH 
for(x=0;x<listOfElements.Count;x++)
{

    int i= listOfElements.IndexOf(oldvalue);

    listOfElements.Insert(i, newvalue);
    listOfElments.RemoveAt(i+1);
}

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionRagavanView Question on Stackoverflow
Solution 1 - C#rokkuchanView Answer on Stackoverflow
Solution 2 - C#Tim SchmelterView Answer on Stackoverflow
Solution 3 - C#Ruslan L.View Answer on Stackoverflow
Solution 4 - C#gzaxxView Answer on Stackoverflow
Solution 5 - C#FejsView Answer on Stackoverflow
Solution 6 - C#Alexander TolstikovView Answer on Stackoverflow
Solution 7 - C#Alex JoligView Answer on Stackoverflow
Solution 8 - C#I.StepView Answer on Stackoverflow
Solution 9 - C#NikView Answer on Stackoverflow
Solution 10 - C#mikeView Answer on Stackoverflow
Solution 11 - C#Tarrah ArshadView Answer on Stackoverflow
Solution 12 - C#DiogoA.View Answer on Stackoverflow