ProgramingTip

두 목록에 연산자를 적용하는 C # 관용적 방법은 무엇입니까?

bestdevel 2020. 11. 30. 19:24
반응형

두 목록에 연산자를 적용하는 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

DotNetFiddle.Net 예제


.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]));
}

물론 이것은 목록의 크기가 같고 변경되지 않는다고 가정합니다. 목록 크기를 미리 알고 있다면 올바른 크기로 인스턴스화 한 다음 루프 중에 요소를 설정하면됩니다.

참고 URL : https://stackoverflow.com/questions/24026624/whats-the-c-idiomatic-way-for-applying-an-operator-across-two-lists

반응형