두 목록에 연산자를 적용하는 C # 관용적 방법은 무엇입니까?
나는 만드는 데 익숙합니다 (다른 언어에서) :
a = 1, 2, 3;
b = 5, 1, 2;
c = a * b; // c = 5, 2, 6
이것은 동일한 크기의 두 개의 목록을 취하고 결과 목록을 위해 한 번에 하나씩 멤버에 함수를 적용합니다. 곱셈 (위)처럼 간단한 함수이거나 더 복잡한 함수일 수 있습니다.
c = b>a ? b-a : 0; // c = 4, 0, 0
C # 에서이 작업을 수행하는 몇 가지 다른 방법을 생각할 수 있습니다 C # 교육을받은 프로그래머가할지 잘 모르겠습니다. C # 세계에서 이에 대해 적절한 방법은 무엇입니까?
(내가 많은 유일한 부분은 c = f(a,b)
. 나는 목록을 만들고 그 요소에 액세스하는 데 익숙합니다.)
var c = a.Zip(b, (x, y) => x * y);
편집 후 더 복잡한 경우 :
var c = a.Zip(b, (x, y) => x > y ? x - y : 0);
참고 Zip
모두 확장 방법 으로 Enumerable
그 위에 작용IEnumerable<T>
으로부터 Queryable
그에 작용IQueryable<T>
이 람다 하나가 주어진 쿼리 제공자 가이 데이터베이스에 SQL 쿼리와 같이 처리 될 수 있음을, 처리 할 수, 또는 것이 가능하므로, .NET의 메모리 내 이외의 다른 방법.
댓글에서 4.0의 새로운 기능이라고 언급했습니다. 3.5를 직접 구현하는 것은 어렵지 않습니다.
public class MyExtraLinqyStuff
{
public static IEnumerable<TResult> Zip<TFirst, TSecond, TResult>(this IEnumerable<TFirst> first, IEnumerable<TSecond> second, Func<TFirst, TSecond, TResult> resultSelector)
{
//Do null checks immediately;
if(first == null)
throw new ArgumentNullException("first");
if(second == null)
throw new ArgumentNullException("second");
if(resultSelector == null)
throw new ArgumentNullException("resultSelector");
return DoZip(first, second, resultSelector);
}
private static IEnumerable<TResult> DoZip<TFirst, TSecond, TResult>(this IEnumerable<TFirst> first, IEnumerable<TSecond> second, Func<TFirst, TSecond, TResult> resultSelector)
{
using(var enF = first.GetEnumerator())
using(var enS = second.GetEnumerator())
while(enF.MoveNext() && enS.MoveNext())
yield return resultSelector(enF.Current, enS.Current);
}
}
.NET2.0 또는 .NET3.0의 경우 주석에서 또 다른 질문에 답하는 확장 메소드가 아니라 동일 할 수 있습니다. NET에서 코딩하는 사람들 사이에서 확고한 인 방법이 없습니다. 우리 중 일부는 툴킷에 위와 같은 방법을 가지고 있었지만 (확장 방법은 그런지) 다른 어떤 것보다 언어와 라이브러리의 영향을 받음 (예 : 내가 알고있는 것들 때문에 위와 같은 일을하고 있습니다). C ++의 STL,하지만 영감의 유일한 원천은 아니 었습니다)
동일한 길이의 목록이있는 .Net 3.5를 가정합니다.
var a = new List<int>() { 1, 2, 3 };
var b = new List<int>() { 5, 1, 2 };
var c = a.Select((x, i) => b[i] * x);
결과 :
5
2
6
.NET 4.0을 사용하지 않는 경우 여기에 Zip을 수행하는 확장 방법을 작성하는 방법이 있습니다.
static IEnumerable<TResult> Zip<TFirst, TSecond, TResult>(this IEnumerable<TFirst> first, IEnumerable<TSecond> second, Func<TFirst, TSecond, TResult> resultSelector)
{
using (IEnumerator<TFirst> e1 = first.GetEnumerator())
using (IEnumerator<TSecond> e2 = second.GetEnumerator())
{
while (e1.MoveNext() && e2.MoveNext())
{
yield return resultSelector(e1.Current, e2.Current);
}
}
}
LINQ가없는 .NET 버전의 경우이를 수행하기 위해 for 루프를 권장합니다.
List<int> list1 = new List<int>(){4,7,9};
List<int> list2 = new List<int>(){11,2,3};
List<int> newList = new List<int>();
for (int i = 0; i < list1.Count; ++i)
{
newList.Add(Math.Max(list1[i], list2[i]));
}
물론 이것은 목록의 크기가 같고 변경되지 않는다고 가정합니다. 목록 크기를 미리 알고 있다면 올바른 크기로 인스턴스화 한 다음 루프 중에 요소를 설정하면됩니다.
'ProgramingTip' 카테고리의 다른 글
C ++ 11에서 허용되지 않는 람다를 재정의하는 이유는 무엇입니까? (0) | 2020.11.30 |
---|---|
밀리 초가있는 epoch 시간을 datetime으로 변환 (0) | 2020.11.30 |
Visual Studio에서 모든 파일을 검색하는 방법 (0) | 2020.11.30 |
비재 귀적 make에 대한 경험은 무엇입니까? (0) | 2020.11.30 |
OOCalc에서 CONCATENATE 함수로 견적을 인용하는 방법 (0) | 2020.11.30 |