Mettre à jour tous les objets d'une collection en utilisant LINQ

y a-t-il un moyen de faire ce qui suit en utilisant LINQ?

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

pour clarifier, je veux itérer à travers chaque objet d'une collection puis mettre à jour une propriété sur chaque objet.

Mon cas d'utilisation, j'ai un tas de commentaires sur un blog, et je tiens à parcourir tous les commentaires sur un blog et l'ensemble de l'datetime sur le blog de +de 10 heures. Je pourrais le faire en SQL, mais je veux le garder dans la couche affaires.

379
demandé sur Peter Mortensen 2008-12-30 01:15:23

15 réponses

alors que vous pouvez utiliser une méthode d'extension ForEach , si vous voulez utiliser juste le framework vous pouvez faire

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

Le ToList est nécessaire afin d'évaluer l'sélectionnez immédiatement en raison de paresseux "évaluation des 151970920" .

658
répondu Cameron MacFarland 2017-06-02 19:56:00
collection.ToList().ForEach(c => c.PropertyToSet = value);
255
répondu Ε Г И І И О 2012-09-02 12:59:48

je fais cela

Collection.All(c => { c.needsChange = value; return true; });
54
répondu Rahul 2013-12-16 08:37:47

j'ai fait trouvé une méthode d'extension qui permettra de faire ce que je veux bien

public static IEnumerable<T> ForEach<T>(
    this IEnumerable<T> source,
    Action<T> act)
{
    foreach (T element in source) act(element);
    return source;
}
18
répondu lomaxx 2008-12-29 22:56:16

utiliser:

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

Je ne suis pas sûr que ce soit abuser LINQ ou pas, mais cela a fonctionné pour moi quand je voulais mettre à jour un élément spécifique dans la liste pour une condition spécifique.

11
répondu Hennish 2016-04-28 11:33:10

il n'y a pas de méthode d'extension intégrée pour faire cela. Bien que la définition est assez simple. En bas du post se trouve une méthode que j'ai définie appelée Iterate. Il peut être utilisé comme

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

Source Itérate

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++;
    }
}
5
répondu JaredPar 2008-12-29 22:22:21

j'ai essayé quelques variantes, et je continue à revenir à la solution de ce gars.

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

encore une fois, c'est la solution de quelqu'un d'autre. Mais j'ai compilé le code dans une petite bibliothèque, et de l'utiliser assez régulièrement.

je vais coller son code ici, pour tout hasard que son site(blog) cesse d'exister à un certain moment dans l'avenir. (Il n'y a rien de pire que de voir un post qui dit "Voici la réponse exacte dont vous avez besoin", cliquez, et URL morte.)

    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; } );
4
répondu granadaCoder 2010-08-17 14:10:14

Non, LINQ ne supporte pas une sorte de mise à jour de masse. La seule façon plus courte serait d'utiliser une ForEach méthode d'extension - pourquoi il n'y a pas de ForEach extension méthode sur IEnumerable?

2
répondu Aaron Powell 2017-05-23 11:47:32

Mes 2 centimes:-

 collection.Count(v => (v.PropertyToUpdate = newValue) == null);
2
répondu AnthonyWJones 2008-12-29 22:38:39

j'ai écrit quelques méthodes d'extension pour m'aider avec ça.

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;
        }
    }
}

je l'utilise comme ceci:

        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

Pour référence l'argument de vérifier:

/// <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
répondu PartTimeIndie 2015-06-25 01:50:13

Voici la méthode d'extension que j'utilise...

    /// <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;
    }
1
répondu Bill Forney 2009-12-15 16:20:56

vous pouvez utiliser Magiq , un cadre d'opération par lots pour LINQ.

1
répondu ivos 2016-04-28 11:32:15

bien que vous ayez spécifiquement demandé une solution linq et que cette question soit assez ancienne, je poste une solution non-linq. Ceci est dû au fait que linq (=lanuguage integrated query ) doit être utilisé pour les requêtes sur les collections. Toutes les méthodes linq ne modifient pas la collection sous-jacente, il suffit de retourner un nouveau (ou plus précis un itérateur à une nouvelle collection). Ainsi, quoi que vous fassiez par exemple avec un Select n'affecte pas le sous-jacent collection, vous obtenez simplement un nouveau.

bien sûr vous pourriez le faire avec un ForEach (qui n'est pas linq, soit dit en passant, mais une extension sur List<T> ). Mais ce littéralement utilise foreach de toute façon mais avec une expression lambda. En dehors de cette chaque linq-méthode en interne itère votre collection par exemple en utilisant foreach ou for , cependant il se cache simplement du client. Je ne considère pas cela plus lisible ou maintenable (pensez à éditer votre code pendant le débogage d'une méthode contenant lambda-expressions).

cela dit, il ne faut pas utiliser Linq pour modifier articles dans votre collection. Une meilleure façon est la solution que vous avez fourni dans votre question. Avec une boucle classique, vous pouvez facilement itérer votre collection et mettre à jour ses éléments. En fait, toutes les solutions basées sur List.ForEach ne sont rien d'autre que beaucoup plus difficile à lire de mon point de vue.

donc vous ne devez pas utiliser linq dans les cas où vous voulez mettre à jour les éléments de votre collection.

1
répondu HimBromBeere 2018-07-25 07:34:11

je suppose que vous voulez changer des valeurs à l'intérieur d'une requête afin que vous puissiez écrire une fonction pour elle""

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; }
}

mais pas shure si c'est ce que vous voulez dire.

0
répondu Stormenet 2008-12-29 22:27:21

vous pouvez utiliser LINQ pour convertir votre collection en tableau et ensuite invoquer tableau.ForEach ():

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

évidemment cela ne fonctionnera pas avec les collections de structures ou les types intégrés comme les entiers ou les chaînes.

0
répondu Tamas Czinege 2008-12-29 23:33:34