답변:
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객체가 세트 (철에 저장되어있는 경우에만 사용됩니다 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;UR 클론 업데이트
dd.Quantity++;목록에서 색인 찾기
int idx = Details.IndexOf(d);(1)에서 발견 된 항목 제거
Details.Remove(d);끼워 넣다
if (idx > -1)
Details.Insert(idx, dd);
else
Details.Insert(Details.Count, dd);