Câu trả lời:
Sử dụng Lambda để tìm chỉ mục trong Danh sách và sử dụng chỉ mục này để thay thế mục danh sách.
List<string> listOfStrings = new List<string> {"abc", "123", "ghi"};
listOfStrings[listOfStrings.FindIndex(ind=>ind.Equals("123"))] = "def";
Equals
bài kiểm tra đơn giản , những bài cũ tốt cũng IndexOf
hoạt động tốt và ngắn gọn hơn - như trong câu trả lời của Tim .
Bạn có thể làm cho nó dễ đọc hơn và hiệu quả hơn:
string oldValue = valueFieldValue.ToString();
string newValue = value.ToString();
int index = listofelements.IndexOf(oldValue);
if(index != -1)
listofelements[index] = newValue;
Điều này chỉ yêu cầu một lần cho chỉ mục. Cách tiếp cận của bạn sử dụng Contains
đầu tiên cần lặp lại tất cả các mục (trong trường hợp xấu nhất), sau đó bạn đang sử dụng IndexOf
cần liệt kê lại các mục.
Equals
hoặc bạn sẽ chỉ tìm thấy đối tượng nếu nó là cùng một tham chiếu. Lưu ý rằng đó string
cũng là một đối tượng (kiểu tham chiếu).
Equals
và bạn cũng phải nhớ rằng đôi khi cùng một lúc bạn phải thực hiệnGetHashCode
GetHashCode
nếu bạn ghi đè Equals
nhưng GetHashCode
chỉ được sử dụng nếu đối tượng được lưu trữ trong một tập hợp (fe Dictionary
hoặc HashSet
), vì vậy nó không được sử dụng với IndexOf
hoặc Contains
chỉ Equals
.
IndexOf
sử dụng EqualityComparer<T>.Default
. Bạn đang nói rằng điều đó cuối cùng sẽ gọi item.Equals(target)
cho từng mục trong danh sách và do đó có hành vi giống hệt như câu trả lời của rokkuchan?
Bạn đang truy cập danh sách của mình hai lần để thay thế một phần tử. Tôi nghĩ rằng for
vòng lặp đơn giản là đủ:
var key = valueFieldValue.ToString();
for (int i = 0; i < listofelements.Count; i++)
{
if (listofelements[i] == key)
{
listofelements[i] = value.ToString();
break;
}
}
Tại sao không sử dụng các phương pháp mở rộng?
Hãy xem xét đoạn mã sau:
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}
Mã nguồn:
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);
}
}
}
Hai phương thức đầu tiên đã được thêm vào để thay đổi các đối tượng của kiểu tham chiếu tại chỗ. Tất nhiên, bạn có thể chỉ sử dụng phương pháp thứ ba cho tất cả các loại.
PS Nhờ quan sát của mike , tôi đã thêm phương thức ReplaceAll.
T
là kiểu tham chiếu hay không là không liên quan. Điều quan trọng là bạn muốn thay đổi (thay đổi) danh sách hay trả lại một danh sách mới. Phương pháp thứ ba tất nhiên sẽ không làm thay đổi danh sách ban đầu, vì vậy bạn không thể chỉ sử dụng phương pháp thứ ba ... . Phương pháp đầu tiên là phương pháp trả lời câu hỏi cụ thể được hỏi. Tuyệt vời mã - chỉ sửa chữa mô tả của bạn về những gì các phương pháp làm :)
Sử dụng FindIndex
và lambda để tìm và thay thế các giá trị của bạn:
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
Bạn có thể sử dụng các tiện ích mở rộng tiếp theo dựa trên điều kiện vị 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;
}
Lưu ý: - Thay vì phần mở rộng ThrowIfArgumentIsNull, bạn có thể sử dụng một cách tiếp cận chung như:
if (argName == null) throw new ArgumentNullException(nameof(argName));
Vì vậy, trường hợp của bạn với các tiện ích mở rộng này có thể được giải quyết như:
string targetString = valueFieldValue.ToString();
listofelements.Replace(x => x.Equals(targetString), value.ToString());
Tôi không biết nó là tốt nhất hay không nhưng bạn cũng có thể sử dụng nó
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");
Hoặc, dựa trên gợi ý của Rusian L., nếu mục bạn đang tìm kiếm có thể nằm trong danh sách nhiều lần ::
[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);
}
tôi thấy tốt nhất để làm điều đó nhanh chóng và đơn giản
tìm mục của bạn trong danh sách
var d = Details.Where(x => x.ProductID == selectedProduct.ID).SingleOrDefault();
tạo bản sao từ hiện tại
OrderDetail dd = d;
Cập nhật bản sao của bạn
dd.Quantity++;
tìm chỉ mục trong danh sách
int idx = Details.IndexOf(d);
loại bỏ mục thành lập trong (1)
Details.Remove(d);
chèn
if (idx > -1)
Details.Insert(idx, dd);
else
Details.Insert(Details.Count, dd);