Answers:
使用Lambda在列表中找到索引,然后使用该索引替换列表项。
List<string> listOfStrings = new List<string> {"abc", "123", "ghi"};
listOfStrings[listOfStrings.FindIndex(ind=>ind.Equals("123"))] = "def";
您可以使其更具可读性和效率:
string oldValue = valueFieldValue.ToString();
string newValue = value.ToString();
int index = listofelements.IndexOf(oldValue);
if(index != -1)
listofelements[index] = newValue;
这只要求一次索引。您的方法使用Contains首先需要循环所有项目的方法(在最坏的情况下),然后使用IndexOf需要再次枚举项目的方法。
Equals或者只有相同引用时您才能找到该对象。请注意,这string也是一个对象(引用类型)。
Equals 并且您还必须记住有时有时必须同时实现GetHashCode
GetHashCode,如果你忽略Equals,但GetHashCode如果对象存储在一组(FE仅用于Dictionary或HashSet),所以它不是与使用IndexOf或Contains只Equals。
IndexOf使用的文档中进行了阅读EqualityComparer<T>.Default。您是说这最终会要求item.Equals(target)列表中的每个项目,因此行为与rokkuchan的答案完全相同吗?
您要访问列表两次以替换一个元素。我认为简单的for循环就足够了:
var key = valueFieldValue.ToString();
for (int i = 0; i < listofelements.Count; i++)
{
if (listofelements[i] == key)
{
listofelements[i] = value.ToString();
break;
}
}
为什么不使用扩展方法?
考虑以下代码:
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}
源代码:
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方法。
T引用类型是否无关紧要。重要的是您是要更改(更改)列表还是返回新列表。当然,第三种方法不会改变原来的列表,所以你不能 只使用第三种方法......。第一种方法是回答所问特定问题的方法。优秀的代码-只需更正您对方法的描述即可:)
您可以使用基于谓词条件的下一个扩展:
/// <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());
或者,根据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);
}
我发现最适合快速简便地做到这一点
在列表中找到您的项目
var d = Details.Where(x => x.ProductID == selectedProduct.ID).SingleOrDefault();从当前克隆
OrderDetail dd = d;更新您的克隆
dd.Quantity++;在列表中查找索引
int idx = Details.IndexOf(d);删除(1)中的已建立项目
Details.Remove(d);插
if (idx > -1)
Details.Insert(idx, dd);
else
Details.Insert(Details.Count, dd);