Tuples listesini kolayca nasıl başlatabilirim?


287

Ben tuples seviyorum . İlgili bilgileri, bir yapı veya sınıf yazmak zorunda kalmadan hızlı bir şekilde gruplandırmanıza olanak tanır. Çok yerelleştirilmiş kodu yeniden düzenlerken bu çok kullanışlıdır.

Ancak bunların bir listesini başlatmak biraz gereksiz görünüyor.

var tupleList = new List<Tuple<int, string>>
{
    Tuple.Create( 1, "cow" ),
    Tuple.Create( 5, "chickens" ),
    Tuple.Create( 1, "airplane" )
};

Daha iyi bir yol yok mu? Sözlük başlatıcı çizgileri boyunca bir çözüm isterim .

Dictionary<int, string> students = new Dictionary<int, string>()
{
    { 111, "bleh" },
    { 112, "bloeh" },
    { 113, "blah" }
};

Benzer bir sözdizimi kullanamaz mıyız?


2
Bu durumda neden olmaz sen bir sözlük yerine tüp listeleriniz kullanılır?
Ed S.

17
@Ed S .: A Dictionary, yinelenen tuşlara izin vermez.
Steven Jeuris

2
@EdS .: Her seferinde bir öğenin yıkanabilir / düzenlenebilir ve benzersiz olduğu iki parçalı değil.

İyi bir nokta, yinelenen anahtar fark etmedi.
Ed S.

Yanıtlar:


280

c # 7.0 bunu yapmanızı sağlar:

  var tupleList = new List<(int, string)>
  {
      (1, "cow"),
      (5, "chickens"),
      (1, "airplane")
  };

Bir Listdiziye değil, sadece bir diziye ihtiyacınız varsa şunları yapabilirsiniz:

  var tupleList = new(int, string)[]
  {
      (1, "cow"),
      (5, "chickens"),
      (1, "airplane")
  };

Ve "Öğe1" ve "Öğe2" yi beğenmediyseniz şunları yapabilirsiniz:

  var tupleList = new List<(int Index, string Name)>
  {
      (1, "cow"),
      (5, "chickens"),
      (1, "airplane")
  };

veya bir dizi için:

  var tupleList = new (int Index, string Name)[]
  {
      (1, "cow"),
      (5, "chickens"),
      (1, "airplane")
  };

hangi yapmanıza izin verir: tupleList[0].IndexvetupleList[0].Name

4.6.2 ve önceki sürümler

Sen yüklemelisiniz System.ValueTupleNuget Paket Yöneticisinden.

Çerçeve 4.7 ve üstü

Çerçeve içine yerleştirilmiştir. Do not yüklemek System.ValueTuple. Aslında, onu kaldırın ve bin dizininden silin.

Not: Gerçek hayatta inek, tavuk veya uçak arasında seçim yapamazdım. Gerçekten paramparça olurdum.


2
Bu bir .net core 2.0 üzerinde kullanılabilir mi?
Алекса Јевтић

2
@ АлексаЈевтић, System.ValueTupleçekirdek 2.0'ı destekler. Ancak, gereksiz paketler sorunlara neden olabileceğinden, önce Nuget olmadan deneyin. Öyle ya da böyle, evet. Mümkünse c # v7 veya üstünü kullanın.
toddmo

1
Kesinlikle mükemmel cevap! Teşekkürler!
Vitox

224

Evet! Bu mümkün .

{} Herhangi çalışır başlatıcısı koleksiyonun sözdizimi IEnumerable bir sahiptir tip Ekleme argümanlar doğru miktarda yöntemi. Yorganın altında nasıl eserlerini rahatsız olmadan, bu araçlar sadece uzanabilir listesi <T> , sizin başlatmak için özel bir Add yöntemi ekleyin T ve bitirdiniz!

public class TupleList<T1, T2> : List<Tuple<T1, T2>>
{
    public void Add( T1 item, T2 item2 )
    {
        Add( new Tuple<T1, T2>( item, item2 ) );
    }
}

Bu, aşağıdakileri yapmanızı sağlar:

var groceryList = new TupleList<int, string>
{
    { 1, "kiwi" },
    { 5, "apples" },
    { 3, "potatoes" },
    { 1, "tomato" }
};

39
Bir dezavantajı sınıfı yazmak zorunda. Senin gibi ben de tuplleri seviyorum çünkü bir sınıf ya da yapı yazmak zorunda değilim.
goodeye

2
@BillW Bunun kesin gönderi olduğundan emin değilim, ama biliyorum ki Jon Skeet bu konuda daha önce yazmıştı .
Steven Jeuris

1
bu işe yarıyor mu groceryList[0] == groceryList[1]veya bir karşılaştırma yapılması mı gerekiyor?
Byyo

Başkalarına bu kodu korumak zorunda kalmamak için ICollection üzerinde Add yöntemleri ile bir Nuget Paketi oluşturdum. Paket için buraya bakın: nuget.org/packages/Naos.Recipes.TupleInitializers Kod için buraya bakın: github.com/NaosProject/Naos.Recipes/blob/master/… Bu, çözümünüzde bir ".Naos" altında bir cs dosyası içerecektir .Recipes "klasörü, bu yüzden bir montaj bağımlılığını sürüklemek zorunda değilsiniz
SFun28

83

C # 6 sadece bunun için yeni bir özellik ekler: uzantı Yöntem ekle. Bu VB.net için her zaman mümkün olmuştur ancak şimdi C # 'da mevcuttur.

Artık Add()sınıflarınıza doğrudan yöntem eklemek zorunda değilsiniz, bunları uzantı yöntemleri olarak uygulayabilirsiniz. Herhangi bir numaralandırılabilir türü bir Add()yöntemle genişletirken , bunu koleksiyon başlatıcı ifadelerinde kullanabilirsiniz. Dolayısıyla, artık listelerden açıkça türemek zorunda değilsiniz ( başka bir cevapta belirtildiği gibi ), basitçe genişletebilirsiniz.

public static class TupleListExtensions
{
    public static void Add<T1, T2>(this IList<Tuple<T1, T2>> list,
            T1 item1, T2 item2)
    {
        list.Add(Tuple.Create(item1, item2));
    }

    public static void Add<T1, T2, T3>(this IList<Tuple<T1, T2, T3>> list,
            T1 item1, T2 item2, T3 item3)
    {
        list.Add(Tuple.Create(item1, item2, item3));
    }

    // and so on...
}

Bu, bunu uygulayan herhangi bir sınıfta yapmanızı sağlar IList<>:

var numbers = new List<Tuple<int, string>>
{
    { 1, "one" },
    { 2, "two" },
    { 3, "three" },
    { 4, "four" },
    { 5, "five" },
};
var points = new ObservableCollection<Tuple<double, double, double>>
{
    { 0, 0, 0 },
    { 1, 2, 3 },
    { -4, -2, 42 },
};

Elbette tuples koleksiyonlarını genişletmekle sınırlı değilsiniz, özel sözdizimini istediğiniz herhangi bir türden koleksiyonlar için olabilir.

public static class BigIntegerListExtensions
{
    public static void Add(this IList<BigInteger> list,
        params byte[] value)
    {
        list.Add(new BigInteger(value));
    }

    public static void Add(this IList<BigInteger> list,
        string value)
    {
        list.Add(BigInteger.Parse(value));
    }
}

var bigNumbers = new List<BigInteger>
{
    new BigInteger(1), // constructor BigInteger(int)
    2222222222L,       // implicit operator BigInteger(long)
    3333333333UL,      // implicit operator BigInteger(ulong)
    { 4, 4, 4, 4, 4, 4, 4, 4 },               // extension Add(byte[])
    "55555555555555555555555555555555555555", // extension Add(string)
};

C # 7, dilde yerleşik olan tuples için destek ekleyecek, ancak bunlar farklı bir tür olacak ( System.ValueTuplebunun yerine). Bu nedenle, değer kümeleri için aşırı yükler eklemek iyi olur, böylece bunları da kullanma seçeneğiniz vardır. Ne yazık ki, ikisi arasında tanımlanmış örtük dönüşüm yoktur.

public static class ValueTupleListExtensions
{
    public static void Add<T1, T2>(this IList<Tuple<T1, T2>> list,
        ValueTuple<T1, T2> item) => list.Add(item.ToTuple());
}

Bu şekilde liste başlatma daha da güzel görünecektir.

var points = new List<Tuple<int, int, int>>
{
    (0, 0, 0),
    (1, 2, 3),
    (-1, 12, -73),
};

Ancak tüm bu sorunlardan geçmek yerine, sadece kullanmaya geçmek daha iyi olabilir ValueTuple.

var points = new List<(int, int, int)>
{
    (0, 0, 0),
    (1, 2, 3),
    (-1, 12, -73),
};

Sonunda kütüphanemi C # 6.0'a güncellerken buna iyi bir göz attım. Bir bakışta iyi görünse de, daha önce TupleList<int, string>.okunan çözümümü tercih ediyorum, çünkü daha okunabilir buluyorum List<Tuple<int, string>>.
Steven Jeuris

1
Bu bir tür takma adın düzeltebileceği bir şeydir. Verilen takma adın kendisi jenerik olamaz ve bu tercih edilebilir. using TupleList = System.Collections.Generic.List<System.Tuple<int, string>>;
Jeff Mercado

Başkalarına bu kodu korumak zorunda kalmamak için ICollection üzerinde Add yöntemleri ile bir Nuget Paketi oluşturdum. Paket için buraya bakın: nuget.org/packages/Naos.Recipes.TupleInitializers Kod için buraya bakın: github.com/NaosProject/Naos.Recipes/blob/master/… Bu, çözümünüzde bir ".Naos" altında bir cs dosyası içerecektir .Recipes "klasörü, bu yüzden bir montaj bağımlılığını sürüklemek zorunda değilsiniz
SFun28

42

Yapıcıyı her seferinde biraz daha iyi çağırarak bunu yapabilirsiniz

var tupleList = new List<Tuple<int, string>>
{
    new Tuple<int, string>(1, "cow" ),
    new Tuple<int, string>( 5, "chickens" ),
    new Tuple<int, string>( 1, "airplane" )
};

6
Çalışmak için orijinal kodu alamadım, bu yüzden olması gerektiğini düşündüğüm şekilde değiştirdim ... bu sözdiziminin "biraz daha iyi" olup olmadığına dair görüşünüzü tersine çevirebilir :)
onedaywhen

5
en azından Tuple.Createbunun yerine kullanın ve tür argümanlarını
çıkartabilirsiniz

28

Eski soru, ama genellikle işleri biraz daha okunabilir hale getirmek için yaptığım şey bu:

Func<int, string, Tuple<int, string>> tc = Tuple.Create;

var tupleList = new List<Tuple<int, string>>
{
    tc( 1, "cow" ),
    tc( 5, "chickens" ),
    tc( 1, "airplane" )
};

.NET'in eski sürümlerinde de çalışır!
Ed Bayiates

1

Super Duper Old biliyorum ama C # 7 kullanarak yöntemler üzerinde Linq ve devam lambdas kullanarak benim parça eklemek istiyorum. Ben bir sınıfta yeniden kullanıldığında DTOs ve anonim projeksiyonlar yerine olarak adlandırılmış tuples kullanmaya çalışın. Evet, alay etmek ve test etmek için hala sınıflara ihtiyacınız var, ancak bir şeyleri satır içi yapmak ve bir sınıfta dolaşmak, bu yeni seçeneğin IMHO'ya sahip olması güzel. Onları

  1. Doğrudan Örnekleme
var items = new List<(int Id, string Name)> { (1, "Me"), (2, "You")};
  1. Mevcut bir koleksiyonun kapalı ve şimdi anonim projeksiyonların nasıl yapıldığına benzer iyi yazılmış tuples dönebilirsiniz.
public class Hold
{
    public int Id { get; set; }
    public string Name { get; set; }
}

//In some method or main console app:
var holds = new List<Hold> { new Hold { Id = 1, Name = "Me" }, new Hold { Id = 2, Name = "You" } };
var anonymousProjections = holds.Select(x => new { SomeNewId = x.Id, SomeNewName = x.Name });
var namedTuples = holds.Select(x => (TupleId: x.Id, TupleName: x.Name));
  1. Tüpleri daha sonra gruplama yöntemleriyle tekrar kullanın veya diğer mantıkta satır içi oluşturmak için bir yöntem kullanın:
//Assuming holder class above making 'holds' object
public (int Id, string Name) ReturnNamedTuple(int id, string name) => (id, name);
public static List<(int Id, string Name)> ReturnNamedTuplesFromHolder(List<Hold> holds) => holds.Select(x => (x.Id, x.Name)).ToList();
public static void DoSomethingWithNamedTuplesInput(List<(int id, string name)> inputs) => inputs.ForEach(x => Console.WriteLine($"Doing work with {x.id} for {x.name}"));

var namedTuples2 = holds.Select(x => ReturnNamedTuple(x.Id, x.Name));
var namedTuples3 = ReturnNamedTuplesFromHolder(holds);
DoSomethingWithNamedTuplesInput(namedTuples.ToList());

Beni yaşlı hissettiriyorsun. :) Burada bir şey eksik olabilirim, ama 'bekletme'yi başlatmak hiç de kısa değil. Bu sorunun tam noktasıydı.
Steven Jeuris

@Steven Jeuris Hayır, haklıydın. 1. Nokta için yanlış kod parçasını kopyalayıp yapıştırdım. 'Gönder'e basmadan önce biraz daha yavaş gitmeliyim.
djangojazz

0

Neden tuplleri seviyorsun? İsimsiz türlere benzer: isim yok. Verilerin yapısını anlayamıyorum.

Klasik dersleri severim

class FoodItem
{
     public int Position { get; set; }
     public string Name { get; set; }
}

List<FoodItem> list = new List<FoodItem>
{
     new FoodItem { Position = 1, Name = "apple" },
     new FoodItem { Position = 2, Name = "kiwi" }
};

3
Dediğim gibi: "Onlar için bir yapı veya sınıf yazmak zorunda kalmadan ilgili bilgileri hızlı bir şekilde gruplandırmanıza izin veriyorlar." Bu sınıfın yalnızca tek bir yöntemde yardımcı veri yapısı olarak kullanılması durumunda, Tuples'ı kullanmayı tercih ederim, bu nedenle gereksiz bir sınıfla bir ad alanını doldurmamak için.
Steven Jeuris

1
Eski Tuple sınıfını düşünüyorsunuz (yapı değil). C # 7, isimlere sahip OLABİLİR yapı tabanlı tuples (yeni ValueTuple türü tarafından desteklenir) ekledi, böylece verilerin yapısını anlayabilirsiniz
Steve Niles

0

Sanırım bir teknik biraz daha kolay ve bundan daha önce bahsedilmemiş:

var asdf = new [] { 
    (Age: 1, Name: "cow"), 
    (Age: 2, Name: "bird")
}.ToList();

Bence bu biraz daha temiz:

var asdf = new List<Tuple<int, string>> { 
    (Age: 1, Name: "cow"), 
    (Age: 2, Name: "bird")
};

Bu, türleri açıkça kullanılıp kullanılmayacağından, kullanmayla aynı şekilde boşuna bahsetmeyi tercih edip etmediğinizi tatmak için daha fazla gelir var. Ben şahsen açık yazmayı tercih ediyorum (örneğin yapıcıda çoğaltılmadığında).
Steven Jeuris

-4
    var colors = new[]
    {
        new { value = Color.White, name = "White" },
        new { value = Color.Silver, name = "Silver" },
        new { value = Color.Gray, name = "Gray" },
        new { value = Color.Black, name = "Black" },
        new { value = Color.Red, name = "Red" },
        new { value = Color.Maroon, name = "Maroon" },
        new { value = Color.Yellow, name = "Yellow" },
        new { value = Color.Olive, name = "Olive" },
        new { value = Color.Lime, name = "Lime" },
        new { value = Color.Green, name = "Green" },
        new { value = Color.Aqua, name = "Aqua" },
        new { value = Color.Teal, name = "Teal" },
        new { value = Color.Blue, name = "Blue" },
        new { value = Color.Navy, name = "Navy" },
        new { value = Color.Pink, name = "Pink" },
        new { value = Color.Fuchsia, name = "Fuchsia" },
        new { value = Color.Purple, name = "Purple" }
    };
    foreach (var color in colors)
    {
        stackLayout.Children.Add(
            new Label
            {
                Text = color.name,
                TextColor = color.value,
            });
        FontSize = Device.GetNamedSize(NamedSize.Large, typeof(Label))
    }

this is a Tuple<Color, string>

Bir Tuple ile değer / ad sözdizimini nasıl elde edersiniz?
Andreas Reiff

Derleyici, anonim türün örtülü olarak
Tuple'e
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.