Linq lambda foreach

Dizideki her dizgiyi kaydırmayı denemek ancak çalışmaz, foreach döngüsü anlamına gelir, lütfen nedenini açıklayın

string s = "keepsakes,table runners,outdoor accessories";
List keys = s.Split(',').ToList();
keys.ForEach(x => x = String.Concat("%", x, "%"));
s = String.Join(",", keys);
Console.WriteLine(s); 

need to get "%keepsakes%,%table runners%,%outdoor accessories%"

UPD: Thanks a lot for suggestions(it's a same way)

but some one can answer why this is works and not works under:

nesne

    public class MyItems
    {
        public string Item { get; set; }
    }

ve func

        string s = "keepsakes,table runners,outdoor accessories";
        List keys = s.Split(',').ToList().Select(x => new MyItems(){ Item = x }).ToList();
        keys.ForEach(x => x.Item = String.Concat("%", x.Item, "%"));
        s = String.Join(",", keys.Select(x => x.Item).ToList());
        Console.WriteLine(s);
4
"işe yaramaz" - tam olarak ne oluyor? Gerçek çıktı nedir? Ayrıca, "dizi" ile ne demek istiyorsunuz?
katma yazar O. R. Mapper, kaynak
Cevabımı güncelledim, lütfen kontrol et
katma yazar codingadventures, kaynak

8 cevap

ForEach içindeki listeyi değiştirmiyorsunuz, yalnızca x yerel değişkenine atanan ancak sonra atılan dizeleri yaratıyorsunuz. -loop için kullanabilirsiniz:

for(int i = 0; i < keys.Count; i++)
{
    keys[i] = String.Concat("%", keys[i], "%");
}

Buna değer, işte temel sorunu çözen kısa LINQ sürümü:

s = string.Join(",", s.Split(',').Select(str => "%" + str + "%"));
10
katma
Bunun dışında, ikinci kod pasajı işe yarıyor, o yüzden anlamıyorum ki "bunun neden işe yaradığını ve altında iş yapmıyor altında birini yanıtlayabilir"
katma yazar Tim Schmelter, kaynak
Bunun yerine neden sınıfınızın mülkü ile işe yaradığını anlamıyorsunuz. Bunun nedeni, MyItems sınıfının bir refernce türüdür ve List.ForEach konumundaki her başvurunun özelliğini değiştiriyorsunuzdur. Bu şekilde, listedeki orijinal nesneyi, referansın kendisinin yerine koymaya çalıştığınız ilk yaklaşımınıza zıt olarak değiştirirsiniz.
katma yazar Tim Schmelter, kaynak
açıklama ile tek cevap!
katma yazar wudzik, kaynak
Lütfen, eğer yapabilirseniz - UPDated cevaplarına bakın.
katma yazar AleksP, kaynak

You can use Join and Select and Format

string s = "keepsakes,table runners,outdoor accessories";

var output = string.Join(",", s.Split(',').Select(x => string.Format("%{0}%", x)));
4
katma
@DaveBish: güncellemen yanlış. İkinci snippet, birincinin aksine çalışıyor ve OP nedenini merak ediyor. Bunun nedeni, dizelerin değişmezliği ile ilgili değildir, ancak List.ForEach içindeki tüm başvuruyu değiştirmeye çalışmak yerine bir başvuru türünün özelliğini değiştirmesidir.
katma yazar Tim Schmelter, kaynak
Sizin için güncelleme eklendi
katma yazar Dave Bish, kaynak
@TimSchmelter Oldukça sağ
katma yazar Dave Bish, kaynak
Lütfen, eğer yapabilirseniz - UPDated cevaplarına bakın.
katma yazar AleksP, kaynak

you can do easier: replace each comma with %,%

string s = "keepsakes,table runners,outdoor accessories";
string s2 = "%" + s.Replace("," , "%,%") + "%";
3
katma
Lütfen, eğer yapabilirseniz - UPDated cevaplarına bakın.
katma yazar AleksP, kaynak

Bir başka yaklaşım (lambdasız):

string result = string.Concat("%", s, "%").Replace(",", "%,%");
2
katma
Lütfen, eğer yapabilirseniz - UPDated cevaplarına bakın.
katma yazar AleksP, kaynak

Başka bir yaklaşım, LINQ yerine Regex kullanıyor olabilir:

string s = "keepsakes,table runners,outdoor accessories";
string pattern = "\\,+";
string replacement = "%,";

Regex rgx = new Regex(pattern);
string result = string.Format("%{0}%", rgx.Replace(s, replacement));

Düzenle:

Dizeyi atamak için bir sınıf kullanarak çalışmasının nedeni, ilk örnekte foreach kullandığınız zamandır:

keys.ForEach(x => x = String.Concat("%", x, "%"));

x, bir dize olan tuşların elemanları, değer olarak ForEach işlevine iletilen bir referanstır. Bunu örnek olarak alın:

var myString = "I'm a string";

Console.WriteLine(myString);

ChangeValue(myString);

Console.WriteLine(myString);

void ChangeValue(string s)
{
    s = "something else";
}

Bu pasajı çalıştırırsanız, referansı değiştirmeye çalıştığımız için ChangeValue yönteminde myString değişmeyeceğini göreceksiniz. Aynı şey ForEach yöntemi için de geçerlidir, bu, ForEach içindeki listenizin değerini değiştirememenizin ana nedenidir.

Yaparsanız, yerine:

class MyClass{
    public string aString;
 }

void ChangeValue(MyClass s)
{
    s.aString = "something else";
}

 var myClass = new MyClass();
 myClass.aString =  "I'm a string";

 Console.WriteLine(myClass.aString);

 ChangeValue(myClass);

 Console.WriteLine(myClass.aString);

İkinci Console.WriteLine öğesinde aString alanının değerinin "başka bir şey" olarak değiştirileceğini kabul edersiniz. Burada , referans türlerinin değere göre nasıl iletildiğinin iyi bir açıklamasıdır

2
katma
@AleksP Cevabımı düzenledim
katma yazar codingadventures, kaynak
Lütfen, eğer yapabilirseniz - UPDated cevaplarına bakın.
katma yazar AleksP, kaynak

List<>.FveyaEach cannot be used to change the contents of the list. You can either create a new list veya use a fveya loop.

keys = keys.Select(x => "%" + x + "%").ToList();

veya

fveya(int i = 0; i < keys.Count; i++)
{
    keys[i] = "%" + keys[i] + "%";
}
1
katma

Diğerlerinin de belirttiği gibi, List.ForEach 'a iletilen lambda bir değer döndürmez.

LINQ tembel, ancak String.Join numaralandırmaya zorlayacak:

var res = String.Join(",", input.Split(',').Select(s => "%" + s + "%"));
1
katma

ForEach, dize listenizi değiştirmez, yalnızca her dize kullanarak bir eylem gerçekleştirir. Bunun yerine bu şekilde yapabilirsiniz:

string s = "keepsakes,table runners,outdoor accessories";
List keys = s.Split(',').Select(x => String.Concat("%", x, "%")).ToList();
s = String.Join(",", keys);
Console.WriteLine(s);
1
katma
Lütfen, eğer yapabilirseniz - UPDated cevaplarına bakın.
katma yazar AleksP, kaynak