Există o modalitate de a face următoarele folosind LINQ?
foreach (var c in collection)
{
c.PropertyToSet = value;
}
Pentru a clarifica, vreau pentru a parcurge fiecare obiect într-o colecție și apoi actualizați o proprietate pe fiecare obiect.
Meu caz de utilizare este că am o grămadă de comentarii pe un blog, și vreau pentru a itera prin fiecare comentariu pe un blog și a stabilit datetime pe blog pentru a fi de +10 ore. Am putea-o face în SQL, dar vreau să-l păstrați în stratul de afaceri.
În timp ce puteți utiliza un "ForEach" metodă de prelungire, dacă doriți să utilizați doar cadrul puteți face
collection.Select(c => {c.PropertyToSet = value; return c;}).ToList();
Anii ToList
este necesar, în scopul de a evalua selectați imediat din cauza leneș de evaluare.
Utilizare:
ListOfStuff.Where(w => w.Thing == value).ToList().ForEach(f => f.OtherThing = vauleForNewOtherThing);
Nu sunt sigur dacă acest lucru este overusing LINQ sau nu, dar ea a lucrat pentru mine, atunci când doresc să actualizare pentru un anumit elementele din listă pentru o anumită condiție.
Nu există nici un built-in extension metodă pentru a face acest lucru. Deși definirea unul este destul de drept înainte. La partea de jos a postului este o metodă am definit numit Repeta. Acesta poate fi folosit ca atât
collection.Iterate(c => { c.PropertyToSet = value;} );
Repeta Sursa
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++;
}
}
Am'am încercat câteva variante pe acest lucru, și mă tot întorc la acest tip de's soluție.
http://www.hookedonlinq.com/UpdateOperator.ashx
Din nou, acest lucru este altcineva's soluție. Dar eu'am compilat codul într-o mică bibliotecă, și să-l utilizați destul de regulat.
Am'm de gând să lipiți codul lui aici, pentru sansa pe care site-ul său(blog) încetează să mai existe la un moment dat în viitor. (Nu's nimic mai rău decât să vezi un post care spune "Aici este exact răspunsul de care ai nevoie", faceți Clic pe, și Mort URL-ul.)
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; } );
Nu, LINQ nu't suport un fel de masă de actualizare. Singura scurt modalitate ar fi de a utiliza o "ForEach" metodă de prelungire - https://stackoverflow.com/questions/101265/why-is-there-not-a-foreach-extension-method-on-the-ienumerable-interface#101303
Am scris câteva metode de extensie care să mă ajute cu asta.
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;
}
}
}
Eu sunt, folosind ca aceasta:
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
Pentru referință argumentul verifica:
/// <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");
}
}
}
}
Puteți folosi LINQ pentru a converti colecția ta de a o matrice și apoi invoca Matrice.ForEach():
Array.ForEach(MyCollection.ToArray(), item=>item.DoSomeStuff());
Evident, acest lucru nu va lucra cu colecții de struct sau incorporat tipuri, cum ar fi numere întregi sau siruri de caractere.
Deși a cerut în mod special pentru un linq-soluție și la această întrebare este destul de vechi am posta un non-linq-soluție. Acest lucru este pentru că linq (=lanuguage integrat interogare) este menit să fie folosit pentru interogări pe colecții. Toate linq-metode nu´t modificarea de fond al sistemului de colectare, au revenirea unul nou (sau mai precis un iterator la o nouă colecție). Astfel, orice ai face de exemplu cu un "Selectați" nu´t efectul de fond al sistemului de colectare, pur și simplu a obține unul nou.
Desigur, ai putea face cu un "ForEach" (care nu e´t linq, apropo, dar o extensie pe Listă
După ce a spus acest shoulnd´t folosi Linq to modificare articole în colecția ta. O modalitate mai bună este soluția de care aveți deja prevăzute în întrebarea dumneavoastră. Cu un clasic buclă puteți repeta cu ușurință colecția dumneavoastră și de a actualiza elementele sale. În fapt, toate aceste solutuions bazându-se pe Listă.ForEach` nu sunt cu nimic diferite, dar mult mai greu de citit din punctul meu de vedere.
Deci nu ar trebui´t folosi linq în acele cazuri în care doriți să actualizare elementele de colectare.
Aici este extinderea metoda am folosi...
/// <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;
}
Presupun că doriți să modificați valorile în interiorul o interogare astfel încât ai putea scrie o funcție pentru a
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; }
}
Dar nu sigur dacă acest lucru este ceea ce vrei să spui.
Să presupunem că avem date ca mai jos,
var items = new List<string>({"123", "456", "789"});
// Like 123 value get updated to 123ABC ..
și dacă vrem să modifice lista și să-i înlocuiască valorile din listă pentru a modifica valorile, apoi creați o nouă listă goală, apoi bucla prin lista de date prin invocarea modificarea metoda pe fiecare articol de pe listă,
var modifiedItemsList = new List<string>();
items.ForEach(i => {
var modifiedValue = ModifyingMethod(i);
modifiedItemsList.Add(items.AsEnumerable().Where(w => w == i).Select(x => modifiedValue).ToList().FirstOrDefault()?.ToString())
});
// assign back the modified list
items = modifiedItemsList;