395

LINQ를 사용하여 다음 작업을 수행 할 수 있습니까?

foreach (var c in collection)
{
    c.PropertyToSet = value;
}

명확히하기 위해 컬렉션의 각 객체를 반복하고 각 객체의 속성을 업데이트하려고합니다.

내 유스 케이스는 블로그 게시물에 대해 많은 의견을 갖고 있으며 블로그 게시물의 각 댓글을 반복하고 블로그 게시물의 날짜 시간을 +10 시간으로 설정하려고합니다. SQL로 할 수는 있지만 비즈니스 계층에 보관하고 싶습니다.


  • 재미있는 질문. 개인적으로 나는 당신이 그것을 어떻게 얻었는지를 더 좋아합니다 - 무엇이 계속 진행되고 있는지 명확히 이해합니다! - noelicus
  • 저는 여기에 같은 질문에 대한 답을 찾기 위해 왔으며, 그것이 쉽고, 코드가 적으며, 미래 개발자들이 당신이 OP에서했던 방식대로 이해하기 쉽도록 결정했습니다. - Casey Crookston
  • LINQ에서 왜 그렇게하고 싶습니까? - Caltor
  • 이 질문은 잘못된 것을 묻습니다. 유일한 정답은 LINQ를 사용하여 데이터 소스를 수정하지 마십시오. - Rango

15 답변


689

당신이 사용할 수있는 동안ForEach확장 방법, 당신이 할 수있는 프레임 워크 만 사용하려면

collection.Select(c => {c.PropertyToSet = value; return c;}).ToList();

그만큼ToList로 인해 즉시 선택을 평가하기 위해 필요합니다.게으른 평가.


  • 나는 이것이 꽤 좋은 해결책이기 때문에 나는 이것을 반대했다 ... 내가 확장 메소드를 좋아하는 유일한 이유는 정확히 무엇이 진행되고 있는지를 이해하는 것이 조금 더 명확해진다는 것이다. 그러나 당신의 솔루션은 여전히 꽤 달콤하다. - lomaxx
  • 컬렉션이ObservableCollection새 목록을 만드는 대신 항목을 변경하는 것이 유용 할 수 있습니다. - Cameron MacFarland
  • @desaivv 예, 이것은 약간의 문법 남용입니다. 따라서 Resharper는 이것을 경고합니다. - Cameron MacFarland
  • IMHO, 이것은 단순한 foreach 루프보다 표현력이 적습니다. ToList ()는 다른 방법으로는 사용되지 않기 때문에 혼란 스럽지만 그렇지 않으면 연기 될 평가를 강요합니다. 프로젝션은 의도 된 용도로 사용되지 않기 때문에 혼란 스럽습니다. 대신 컬렉션의 요소를 반복하고 업데이트 할 수 있도록 속성에 액세스 할 수 있습니다. 내 마음에있는 유일한 질문은 foreach 루프가 Parallel.ForEach를 사용하여 병렬 처리에서 이익을 얻을 수 있는지 여부입니다.하지만 그 질문은 다른 질문입니다. - Philippe
  • 누군가이 이유가 가장 높은 투표 응답이라고 설명 할 수 있습니까? ForEach를 사용하면 더 나은 이유는 무엇입니까? - Igor Meszaros

263

collection.ToList().ForEach(c => c.PropertyToSet = value);


  • 둘 이상의 속성을 업데이트하려면 어떻게해야합니까? - iamCR
  • @SanthoshKumar : 사용collection.ToList().ForEach(c => { c.Property1ToSet = value1; c.Property2ToSet = value2; }); - Ε Г И І И О
  • 나는 VB.NET을 사용하고 있는데, 이것은 나를 위해 일하지 않는다 :( - kbvishnu
  • 이것은 새로운 목록을 만드는 대신 목록을 업데이트하는 Cameron MacFarland의 대답에 비해 장점이 있습니다. - Simon Tewsi
  • 와,이 대답은 정말로 유용하지 않습니다. 루프를 사용할 수 있도록 새 컬렉션 만들기 - Rango

56

나는 이것을하고있다.

Collection.All(c => { c.needsChange = value; return true; });


  • 나는 이것이 이것을하는 가장 깨끗한 방법이라고 생각한다. - wcm
  • 이 접근법은 확실히 효과가 있지만 그 의도를 위반합니다.All()다른 사람이 코드를 읽을 때 혼란을 야기 할 수 있습니다. - Tom Baxter
  • 이 방법은 더 좋습니다. 각 루프를 사용하는 대신 All을 사용하십시오. - UJS
  • ToList ()를 불필요하게 호출하는 것보다이 방법을 더 선호합니다. All ()을 사용하는 것에 대해 약간의 오해를 불러 일으킬지라도. - iupchris10

19

나는 실제로확장 메소드를 찾았습니다.그게 내가 원하는 것을 잘 할거야.

public static IEnumerable<T> ForEach<T>(
    this IEnumerable<T> source,
    Action<T> act)
{
    foreach (T element in source) act(element);
    return source;
}


  • 멋진 :) Lomaxx, 삽화를 추가하여 친구들이 ' 액션 ' (붐 티쉬!). - Pure.Krome
  • 당신이 정말로 피하기를 원한다면 이것은 유일한 유용한 접근법이다.foreach-loop (이유가 무엇이든). - Rango
  • 아직 피하지 않는 @Rangoforeach코드 자체에foreach고리 - GoldBishop
  • @ GoldBishop 확실히, 메서드는 루프를 숨 깁니다. - Rango

12

용도:

ListOfStuff.Where(w => w.Thing == value).ToList().ForEach(f => f.OtherThing = vauleForNewOtherThing);

이것이 LINQ를 과용하는지 확실하지 않지만 특정 조건을 위해 목록의 특정 항목을 업데이트하려고 할 때 저에게 효과적입니다.


5

이를 수행하는 기본 제공 확장 방법이 없습니다. 하나를 정의하는 것은 상당히 간단합니다. 게시물의 맨 아래에 Iterate라고 정의 된 메소드가 있습니다. 그렇게 사용할 수 있습니다.

collection.Iterate(c => { c.PropertyToSet = value;} );

소스 반복

public static void Iterate<T>(this IEnumerable<T> enumerable, Action<T> callback)
{
    if (enumerable == null)
    {
        throw new ArgumentNullException("enumerable");
    }

    IterateHelper(enumerable, (x, i) => callback(x));
}

public static void Iterate<T>(this IEnumerable<T> enumerable, Action<T,int> callback)
{
    if (enumerable == null)
    {
        throw new ArgumentNullException("enumerable");
    }

    IterateHelper(enumerable, callback);
}

private static void IterateHelper<T>(this IEnumerable<T> enumerable, Action<T,int> callback)
{
    int count = 0;
    foreach (var cur in enumerable)
    {
        callback(cur, count);
        count++;
    }
}


  • 반복, 스칼라 값을 반환하는 Count, Sum, Avg 또는 다른 기존 확장 메서드가 잘못 되었습니까? - AnthonyWJones
  • 이것은 내가 원하는 것 그러나 조금 .. 관련된 것에 꽤 가깝다. 게시 한 블로그 게시물은 비슷한 구현이지만 코드 줄이 더 적습니다. - lomaxx
  • IterateHelper는 잔인한 것처럼 보입니다. 인덱스를 사용하지 않는 오버로드로 인해 더 많은 추가 작업이 필요하게됩니다. 인덱스를 사용하는 람다로 콜백을 변환하고 사용되지 않는 카운트를 유지하십시오. 어쨌든 forloop을 사용하는 것이 효율적인 방법이므로 재사용을 이해하고 있습니다. - Cameron MacFarland
  • @ 카메론, IterateHelper는 2 가지 용도로 사용됩니다. 1) 단일 구현 및 2) 호출 시간 대 사용시 ArgumentNullException을 throw 할 수 있습니다. C #iterators는 지연 실행되고, 도우미는 반복 중에 throw되는 예외의 이상한 동작을 방지합니다. - JaredPar
  • @ JaredPar : 반복자를 사용하지 않는 것을 제외하고. 수확량 계산서가 없습니다. - Cameron MacFarland

4

나는 이것에 약간 변이를 시도하고, 나는이 녀석 해결책으로 돌아 간다.

http://www.hookedonlinq.com/UpdateOperator.ashx

다시 말하지만, 이것은 다른 누군가의 해결책입니다. 하지만이 코드를 작은 라이브러리로 컴파일하고 상당히 규칙적으로 사용합니다.

나는 그의 사이트 (블로그)가 미래의 어떤 시점에 존재하지 않게 될 가능성에 대비하여 코드를 여기에 붙여 넣을 것이다. ( "필요한 정확한 대답은 여기 있습니다", 클릭 및 죽은 URL) 게시물을 보는 것보다 더 나쁜 것은 없습니다.

    public static class UpdateExtensions {

    public delegate void Func<TArg0>(TArg0 element);

    /// <summary>
    /// Executes an Update statement block on all elements in an IEnumerable<T> sequence.
    /// </summary>
    /// <typeparam name="TSource">The source element type.</typeparam>
    /// <param name="source">The source sequence.</param>
    /// <param name="update">The update statement to execute for each element.</param>
    /// <returns>The numer of records affected.</returns>
    public static int Update<TSource>(this IEnumerable<TSource> source, Func<TSource> update)
    {
        if (source == null) throw new ArgumentNullException("source");
        if (update == null) throw new ArgumentNullException("update");
        if (typeof(TSource).IsValueType)
            throw new NotSupportedException("value type elements are not supported by update.");

        int count = 0;
        foreach (TSource element in source)
        {
            update(element);
            count++;
        }
        return count;
    }
}



int count = drawingObjects
        .Where(d => d.IsSelected && d.Color == Colors.Blue)
        .Update(e => { e.Color = Color.Red; e.Selected = false; } );


  • 당신은Action<TSource>추가 대리인을 만드는 대신 그것은 그 당시에는 사용 가능하지 않았을 수도 있습니다. - Frank J

3

아니요, LINQ는 대량 업데이트 방식을 지원하지 않습니다. 유일한더 짧은방법은ForEach확장 메소드 -IEnumerable에 ForEach 확장 메서드가없는 이유는 무엇입니까?


3

내 2 페니 : -

 collection.Count(v => (v.PropertyToUpdate = newValue) == null);


  • 나는 그 생각이 마음에 들지만, 코드가하는 일을 명확히 밝히지는 않았다. - lomaxx
  • 예, 프로덕션 코드에서이 기능을 사용하고 싶지 않습니다. - Cameron MacFarland

2

나는 그것을 돕기 위해 몇 가지 확장 방법을 썼다.

namespace System.Linq
{
    /// <summary>
    /// Class to hold extension methods to Linq.
    /// </summary>
    public static class LinqExtensions
    {
        /// <summary>
        /// Changes all elements of IEnumerable by the change function
        /// </summary>
        /// <param name="enumerable">The enumerable where you want to change stuff</param>
        /// <param name="change">The way you want to change the stuff</param>
        /// <returns>An IEnumerable with all changes applied</returns>
        public static IEnumerable<T> Change<T>(this IEnumerable<T> enumerable, Func<T, T> change  )
        {
            ArgumentCheck.IsNullorWhiteSpace(enumerable, "enumerable");
            ArgumentCheck.IsNullorWhiteSpace(change, "change");

            foreach (var item in enumerable)
            {
                yield return change(item);
            }
        }

        /// <summary>
        /// Changes all elements of IEnumerable by the change function, that fullfill the where function
        /// </summary>
        /// <param name="enumerable">The enumerable where you want to change stuff</param>
        /// <param name="change">The way you want to change the stuff</param>
        /// <param name="where">The function to check where changes should be made</param>
        /// <returns>
        /// An IEnumerable with all changes applied
        /// </returns>
        public static IEnumerable<T> ChangeWhere<T>(this IEnumerable<T> enumerable, 
                                                    Func<T, T> change,
                                                    Func<T, bool> @where)
        {
            ArgumentCheck.IsNullorWhiteSpace(enumerable, "enumerable");
            ArgumentCheck.IsNullorWhiteSpace(change, "change");
            ArgumentCheck.IsNullorWhiteSpace(@where, "where");

            foreach (var item in enumerable)
            {
                if (@where(item))
                {
                    yield return change(item);
                }
                else
                {
                    yield return item;
                }
            }
        }

        /// <summary>
        /// Changes all elements of IEnumerable by the change function that do not fullfill the except function
        /// </summary>
        /// <param name="enumerable">The enumerable where you want to change stuff</param>
        /// <param name="change">The way you want to change the stuff</param>
        /// <param name="where">The function to check where changes should not be made</param>
        /// <returns>
        /// An IEnumerable with all changes applied
        /// </returns>
        public static IEnumerable<T> ChangeExcept<T>(this IEnumerable<T> enumerable,
                                                     Func<T, T> change,
                                                     Func<T, bool> @where)
        {
            ArgumentCheck.IsNullorWhiteSpace(enumerable, "enumerable");
            ArgumentCheck.IsNullorWhiteSpace(change, "change");
            ArgumentCheck.IsNullorWhiteSpace(@where, "where");

            foreach (var item in enumerable)
            {
                if (!@where(item))
                {
                    yield return change(item);
                }
                else
                {
                    yield return item;
                }
            }
        }

        /// <summary>
        /// Update all elements of IEnumerable by the update function (only works with reference types)
        /// </summary>
        /// <param name="enumerable">The enumerable where you want to change stuff</param>
        /// <param name="update">The way you want to change the stuff</param>
        /// <returns>
        /// The same enumerable you passed in
        /// </returns>
        public static IEnumerable<T> Update<T>(this IEnumerable<T> enumerable,
                                               Action<T> update) where T : class
        {
            ArgumentCheck.IsNullorWhiteSpace(enumerable, "enumerable");
            ArgumentCheck.IsNullorWhiteSpace(update, "update");
            foreach (var item in enumerable)
            {
                update(item);
            }
            return enumerable;
        }

        /// <summary>
        /// Update all elements of IEnumerable by the update function (only works with reference types)
        /// where the where function returns true
        /// </summary>
        /// <param name="enumerable">The enumerable where you want to change stuff</param>
        /// <param name="update">The way you want to change the stuff</param>
        /// <param name="where">The function to check where updates should be made</param>
        /// <returns>
        /// The same enumerable you passed in
        /// </returns>
        public static IEnumerable<T> UpdateWhere<T>(this IEnumerable<T> enumerable,
                                               Action<T> update, Func<T, bool> where) where T : class
        {
            ArgumentCheck.IsNullorWhiteSpace(enumerable, "enumerable");
            ArgumentCheck.IsNullorWhiteSpace(update, "update");
            foreach (var item in enumerable)
            {
                if (where(item))
                {
                    update(item);
                }
            }
            return enumerable;
        }

        /// <summary>
        /// Update all elements of IEnumerable by the update function (only works with reference types)
        /// Except the elements from the where function
        /// </summary>
        /// <param name="enumerable">The enumerable where you want to change stuff</param>
        /// <param name="update">The way you want to change the stuff</param>
        /// <param name="where">The function to check where changes should not be made</param>
        /// <returns>
        /// The same enumerable you passed in
        /// </returns>
        public static IEnumerable<T> UpdateExcept<T>(this IEnumerable<T> enumerable,
                                               Action<T> update, Func<T, bool> where) where T : class
        {
            ArgumentCheck.IsNullorWhiteSpace(enumerable, "enumerable");
            ArgumentCheck.IsNullorWhiteSpace(update, "update");

            foreach (var item in enumerable)
            {
                if (!where(item))
                {
                    update(item);
                }
            }
            return enumerable;
        }
    }
}

나는 이것을 다음과 같이 사용하고있다.

        List<int> exampleList = new List<int>()
            {
                1, 2 , 3
            };

        //2 , 3 , 4
        var updated1 = exampleList.Change(x => x + 1);

        //10, 2, 3
        var updated2 = exampleList
            .ChangeWhere(   changeItem => changeItem * 10,          // change you want to make
                            conditionItem => conditionItem < 2);    // where you want to make the change

        //1, 0, 0
        var updated3 = exampleList
            .ChangeExcept(changeItem => 0,                          //Change elements to 0
                          conditionItem => conditionItem == 1);     //everywhere but where element is 1

참고로 인수 검사 :

/// <summary>
/// Class for doing argument checks
/// </summary>
public static class ArgumentCheck
{


    /// <summary>
    /// Checks if a value is string or any other object if it is string
    /// it checks for nullorwhitespace otherwhise it checks for null only
    /// </summary>
    /// <typeparam name="T">Type of the item you want to check</typeparam>
    /// <param name="item">The item you want to check</param>
    /// <param name="nameOfTheArgument">Name of the argument</param>
    public static void IsNullorWhiteSpace<T>(T item, string nameOfTheArgument = "")
    {

        Type type = typeof(T);
        if (type == typeof(string) ||
            type == typeof(String))
        {
            if (string.IsNullOrWhiteSpace(item as string))
            {
                throw new ArgumentException(nameOfTheArgument + " is null or Whitespace");
            }
        }
        else
        {
            if (item == null)
            {
                throw new ArgumentException(nameOfTheArgument + " is null");
            }
        }

    }
}


2

당신은 특별히 linq - 솔루션을 요청했지만이 질문은 꽤 오래 전 non-linq 솔루션을 게시합니다. 이것은 linq (= lanuguage 통합질문)는 컬렉션에 대한 쿼리에 사용됩니다. 모든 linq 메서드는 기본 컬렉션을 수정하지 않습니다.반환새로운 컬렉션 (또는 새로운 컬렉션의 반복자) 따라서 무엇을 하든지. ~와Select기본 컬렉션에 영향을 미치지 않으면 새 컬렉션을 얻으십시오.

물론 너.할 수 있었다그것으로해라.ForEach(linq는 아니지만 그런데 확장 기능은List<T>). 하지만 이것은말 그대로용도foreach어쨌든 람다 표현식을 사용합니다. 이 외에도...마다linq-method는 내부적으로 컬렉션을 반복합니다. 사용하여foreach또는for그러나 클라이언트에서 단순히 숨 깁니다. 나는 이것을 더 이상 읽을 수없고 유지할 수 없다고 생각하지 않는다. (람다 표현식을 포함하는 메소드를 디버깅하는 동안 코드를 편집하는 것을 생각해 보라.)

이 shoulndt는 Linq를 사용하여수정하다컬렉션의 항목 더 나은 방법은 이미 질문에 제공 한 솔루션입니다. 클래식 루프를 사용하면 컬렉션을 쉽게 반복하고 항목을 업데이트 할 수 있습니다. 사실 이러한 모든 해결책은List.ForEach내 관점에서 읽는 것이 다르지만 훨씬 더 어렵습니다.

그래서 당신이 원하는 경우 linq을 사용해서는 안됩니다.최신 정보컬렉션의 요소.


  • 오프 주제 : 나는 동의하고, "고성능 LINQ 체인"을 요청하는 사람들의 사례, 예를 들어 단일 루프로 수행 할 수있는 작업을 수행하는 사람들의 사례 인 LINQ의 많은 인스턴스가 있습니다. LINQ를 사용하지 않는 것이 감사합니다. 나에게 너무 뿌리 내리고, 전형적으로 그것을 사용하지 않는다. 사람들이 LINQ 체인을 사용하여 단일 작업을 수행하는 것을 보았습니다. LINQ 명령을 사용하면 매번 다른 작업을 생성 할 때마다이를 인식하지 못합니다.for루프 "후드"아래에 위치한다. 나는 단순한 작업을하는 덜 장황한 방법을 만들기 위해 표준적인 코딩을 대신 할 수있는 합성 설탕이라고 생각한다. - ForeverZer0

1

LINQ를 사용하여 컬렉션을 배열로 변환 한 다음 Array.ForEach ()를 호출 할 수 있습니다.

Array.ForEach(MyCollection.ToArray(), item=>item.DoSomeStuff());

분명히 이것은 정수 또는 문자열과 같은 구조체 또는 inbuilt 형식의 컬렉션과 함께 작동하지 않습니다.


1

내가 사용하는 확장 방법은 다음과 같습니다.

    /// <summary>
    /// Executes an Update statement block on all elements in an  IEnumerable of T
    /// sequence.
    /// </summary>
    /// <typeparam name="TSource">The source element type.</typeparam>
    /// <param name="source">The source sequence.</param>
    /// <param name="action">The action method to execute for each element.</param>
    /// <returns>The number of records affected.</returns>
    public static int Update<TSource>(this IEnumerable<TSource> source, Func<TSource> action)
    {
        if (source == null) throw new ArgumentNullException("source");
        if (action == null) throw new ArgumentNullException("action");
        if (typeof (TSource).IsValueType)
            throw new NotSupportedException("value type elements are not supported by update.");

        var count = 0;
        foreach (var element in source)
        {
            action(element);
            count++;
        }
        return count;
    }


  • " 값 유형 요소가 업데이트에서 지원되지 않습니다 "라는 이유 아무것도 방해하지 않는다! - abatishchev
  • 그것은 제가 작업하고있는 프로젝트에 특유한 것입니다. 대부분의 경우 문제가되지 않을 것이라고 생각합니다. 최근에 저는이를 다시 작성하여 Run (...)으로 이름을 바꾸고 값 유형을 제거하고 void를 반환하도록 변경하고 카운트 코드를 삭제했습니다. - Bill Forney
  • 그것은 Reactive extensions Run method와 정렬됩니다 ... - Bill Forney
  • 그 이상은 무엇인가?List<T>.ForEach또한 그렇지만 모든 것을 위해서IEnumerable. - HimBromBeere
  • 이제 이것을 다시 살펴보면 foreach 루프 만 사용한다고 말할 수 있습니다. 이런 식으로 사용하는 것의 유일한 이점은 메서드를 함께 체인화하고 함수를 실행 한 후에 체인에서 계속하기 위해 함수에서 열거 가능한 값을 반환하려는 경우입니다. 그렇지 않으면 이것은 단지 도움이되지 않는 추가 메소드 호출 일뿐입니다. - Bill Forney

1

당신이 사용할 수있는Magiq, LINQ를위한 배치 작업 프레임 워크.


0

나는 당신이 그것에 대한 함수를 작성할 수 있도록 쿼리 내부의 값을 변경하기를 원한다고 가정합니다.

void DoStuff()
{
    Func<string, Foo, bool> test = (y, x) => { x.Bar = y; return true; };
    List<Foo> mylist = new List<Foo>();
    var v = from x in mylist
            where test("value", x)
            select x;
}

class Foo
{
    string Bar { get; set; }
}

그러나 그것이 당신이 의미하는 것이면 shure하지 마라.


  • 이것은 올바른 방향의 일종으로, v를 열거 할 것이 필요합니다. 그렇지 않으면 아무것도하지 않습니다. - AnthonyWJones

연결된 질문


관련된 질문

최근 질문