如何以最佳方式替换列表项


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

我已经像上面一样替换了。除此以外,还有其他最佳方法吗?

Answers:


109

使用Lambda在列表中找到索引,然后使用该索引替换列表项。

List<string> listOfStrings = new List<string> {"abc", "123", "ghi"};
listOfStrings[listOfStrings.FindIndex(ind=>ind.Equals("123"))] =  "def";

14
检查-1!如果该商品不在收藏中
Surender Singh Malik 2015年

3
再加上一个可使用FindIndex的内容
亚伦·巴克

2
这是最好的通用答案恕我直言,因为它也可以用于比较对象。
Simcha Khabinsky

请参阅Fej的增强功能,该功能检查-1。尽管对于一个简单的Equals测试来说,好的旧版也IndexOf可以工作,并且也更简洁-正如Tim的回答
制造商史蒂夫(Steve),

109

您可以使其更具可读性和效率:

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

这只要求一次索引。您的方法使用Contains首先需要循环所有项目的方法(在最坏的情况下),然后使用IndexOf需要再次枚举项目的方法。


2
这是查找文字(整数,字符串)的正确答案,但对于查找对象却不是很好。但是,我很喜欢rokkuchan的答案,因为它具有通用性。
Simcha Khabinsky

1
@SimchaKhabinsky:确实也可以使用引用类型,该类型只需要重写即可,Equals或者只有相同引用时您才能找到该对象。请注意,这string也是一个对象(引用类型)。
蒂姆·施密特

是的,你是对的。但是,我看到许多开发人员没有记得要实现,Equals 并且您还必须记住有时有时必须同时实现GetHashCode
Simcha Khabinsky

1
@SimchaKhabinsky:是的,你应该总是重写GetHashCode,如果你忽略Equals,但GetHashCode如果对象存储在一组(FE仅用于DictionaryHashSet),所以它不是与使用IndexOfContainsEquals
蒂姆·施密特

蒂姆,我对这个vs rokkuchan有疑问。我在IndexOf使用的文档中进行了阅读EqualityComparer<T>.Default。您是说这最终会要求item.Equals(target)列表中的每个项目,因此行为与rokkuchan的答案完全相同吗?
制造商史蒂夫·

16

您要访问列表两次以替换一个元素。我认为简单的for循环就足够了:

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

1
@gzaxx。“您要访问列表两次以替换一个元素。我认为简单的for循环就足够了”。您要访问for循环伴侣多少次?
2014年

5
@Pap抱歉,我不够清楚。他重复了两次列表(首先检查项目是否在列表中,第二次获得项目索引)。
gzaxx

13

为什么不使用扩展方法?

考虑以下代码:

        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}
  • 没有代码重复
  • 无需键入长linq表达式
  • 无需额外使用

源代码:

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("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("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("source");

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

添加了前两种方法以更改引用类型的对象。当然,您可以对所有类型仅使用第三种方法。

PS由于mike的观察,我添加了ReplaceAll方法。


1
关于“就地更改引用类型的对象” - T引用类型是否无关紧要。重要的是您是要更改(更改)列表还是返回新列表。当然,第三种方法不会改变原来的列表,所以你不能 只使用第三种方法......。第一种方法是回答所问特定问题的方法。优秀的代码-只需更正您对方法的描述即可:)
ToolmakerSteve

7

按照rokkuchan的回答,只需稍作升级:

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

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

5

使用FindIndex和lambda查找并替换您的值:

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

3

您可以使用基于谓词条件的下一个扩展:

    /// <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;
    }

注意:-代替ThrowIfArgumentIsNull扩展,可以使用如下通用方法:

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

因此,使用这些扩展名的情况可以解决为:

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

1

我不是最好还是不是,但您也可以使用它

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");

1

或者,根据Rusian L.的建议,如果要搜索的项目可以多次出现在列表中:

[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);
}

1

您可以像这样使用lambda表达式。

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

0

我发现最适合快速简便地做到这一点

  1. 在列表中找到您的项目

    var d = Details.Where(x => x.ProductID == selectedProduct.ID).SingleOrDefault();
  2. 从当前克隆

    OrderDetail dd = d;
  3. 更新您的克隆

    dd.Quantity++;
  4. 在列表中查找索引

    int idx = Details.IndexOf(d);
  5. 删除(1)中的已建立项目

      Details.Remove(d);
  6.  if (idx > -1)
          Details.Insert(idx, dd);
      else
          Details.Insert(Details.Count, dd);
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.