Listedeki <T> nesnedeki bir özelliğe göre sıralama


1248

Aradım bir sınıf var Orderözelliklere gibi vardır OrderId, OrderDate, Quantity, ve Total. Bunun bir listesi varOrder sınıfın :

List<Order> objListOrder = new List<Order>();
GetOrderList(objListOrder); // fill list of orders

Şimdi listeyi bir özelliğe göre sıralamak istiyorum Order nesnenin , örneğin sipariş tarihine veya sipariş kimliğine göre sıralamam gerekiyor.

Bunu C # ile nasıl yapabilirim?


9
Bekle - Her iki sipariş tarihine göre sıralamak istiyorsanız ve sipariş id? Çünkü cevapların çoğu sadece birine ya da diğerine göre sıraladığınızı varsayıyor gibi görünüyor.
GalacticCowboy

@GalacticCowboy, @GenericTypeTea: Soru " Sipariş nesnesinin bir özelliğine göre listeyi sıralamak istiyorum" diyor , ancak başka bir yerde tamamen açık olmadığını kabul ediyorum. Her iki durumda da, bir veya birkaç özelliğe göre sıralamanız gerekip gerekmediği çok büyük bir fark yaratmaz.
LukeH

@LukeH - Tekrar okudum ve katılıyorum. 'Listeyi bir özelliğe göre sıralamak istiyorum' ... ve 'sipariş tarihi veya sipariş kimliği'. Tüm cevaplar arasında tüm üslerimiz var :).
djdd87

Yanıtlar:


1807

Aklıma gelen en kolay yol Linq kullanmaktır:

List<Order> SortedList = objListOrder.OrderBy(o=>o.OrderDate).ToList();

22
bunu azalan düzende nasıl sıralayabilirim.
Sevimli Ayı

229
@BonusKun Listesi <Order> SortedList = objListOrder. OrderByDescending (o => o.OrderDate) .ToList ();
javajavajavajavajava

77
bunun, bellekteki tüm öğelerle birlikte performans açısından sorunlu olabilecek yepyeni bir liste oluşturduğunu unutmayın .
staafl

14
@staafl listWithObjects = listWithObjects.OrderByDescending(o => o.Status).ToList();böyle bir çaba için yeterli olacak mı?
Andrew Grinder

28
@staafl Nesnelerin kendilerinin farkında olduğum kadar çoğaltılmaması yerine bir nesne referansları listesi sipariş ediyoruz. Bu, referanslar listesinin kullandığı belleği iki katına çıkarsa da, aslında tüm nesneleri kendileri çoğaltmak kadar kötü değil, bu nedenle büyük veri kümeleriyle uğraştığımız ve onları bellekte tutmamızın dışındaki senaryolarda zaten bir sorun var, yeterli olmalı.
Lazarus

798

Listeyi yerinde sıralamanız gerekiyorsa Sort, bir Comparison<T>temsilci ileterek yöntemi kullanabilirsiniz :

objListOrder.Sort((x, y) => x.OrderDate.CompareTo(y.OrderDate));

Yerinde sıralamak yerine yeni, sıralı bir sıra oluşturmayı tercih ediyorsanız OrderBy, diğer yanıtlarda belirtildiği gibi LINQ yöntemini kullanabilirsiniz .


30
Evet, bu "doğru" cevaptır ve yeni bir IEnumerable oluşturmak ve ardından yeni bir listeye dönüştürmekten çok daha verimli olmalıdır.
Jonathan Wood

45
Tabii ki, azalan sıralamaya ihtiyacınız varsa , okun sağ tarafında değiştirin xve değiştirin . y=>
Jeppe Stig Nielsen

15
Listeyi yerinde sıralayan gerçek cevap
Mitchell Currie

3
@PimBrouwers Bu daha iyi bir seçenek dönemi. Kullandığınız bellek miktarı bir sorun olmasa bile, bu çözüm, son derece pahalı olan gereksiz bellek ayırmayı önler. Bu seçenek kodlama kadar basit ve daha hızlı bir büyüklük sırasıdır.
Cdaragorn

12
@JonSchneider Nullable<>( DateTime?örnek olarak alın) için .Sort((x, y) => Nullable.Compare(x.OrderDate, y.OrderDate))null değerini tüm null olmayan değerlerden önce görürsünüz . Tam olarak aynı .Sort((x, y) => Comparer<DateTime?>.Default.Compare(x.OrderDate, y.OrderDate).
Jeppe Stig Nielsen

219

Bunu Net2.0 üzerinde LINQ olmadan yapmak için:

List<Order> objListOrder = GetOrderList();
objListOrder.Sort(
    delegate(Order p1, Order p2)
    {
        return p1.OrderDate.CompareTo(p2.OrderDate);
    }
);

Net3.0 kullanıyorsanız, LukeH'nin cevabı peşinde olduğunuz şeydir.

Birden çok mülke göre sıralamak için, yine de bir temsilci içinde yapabilirsiniz. Örneğin:

orderList.Sort(
    delegate(Order p1, Order p2)
    {
        int compareDate = p1.Date.CompareTo(p2.Date);
        if (compareDate == 0)
        {
            return p2.OrderID.CompareTo(p1.OrderID);
        }
        return compareDate;
    }
);

Bu , azalan orderIds ile artan tarihler verir.

Ancak, kod yeniden kullanım olmadan birçok yer anlamına gelecektir delege yapışmasını tavsiye etmem. BirIComparer ve bunu Sortyönteminize aktarmanız yeterlidir. Buraya bakın .

public class MyOrderingClass : IComparer<Order>
{
    public int Compare(Order x, Order y)
    {
        int compareDate = x.Date.CompareTo(y.Date);
        if (compareDate == 0)
        {
            return x.OrderID.CompareTo(y.OrderID);
        }
        return compareDate;
    }
}

Ve sonra bu IComparer sınıfını kullanmak için, onu hemen örnekleyin ve Sort yönteminize iletin:

IComparer<Order> comparer = new MyOrderingClass();
orderList.Sort(comparer);

1
Mükemmel yanıt ve daha iyi bir kapsülleme sağlayan orijinal listenin (LINQ sürümünün her zaman yapacağı) yeniden başlatılmasını koruduğu için doğru olanı olmalıdır.
Jeb

@wonton, hayır. Fikir, IComparerbize polimorfik davranışlar veren farklı uygulamalara sahip olabilmektir .
radarbob

Benim için çalıştı. Sıralama seçenekleri ile bunun bir sürümünü yayınladım.
Jack Griffin

109

Bir liste sipariş etmenin en basit yolu kullanmaktır OrderBy

 List<Order> objListOrder = 
    source.OrderBy(order => order.OrderDate).ToList();

SQL Sorgusu gibi birden çok sütunla sipariş vermek isterseniz.

ORDER BY OrderDate, OrderId

Bunu başarmak için ThenByaşağıdaki gibi kullanabilirsiniz .

  List<Order> objListOrder = 
    source.OrderBy(order => order.OrderDate).ThenBy(order => order.OrderId).ToList();

32

Dediğin gibi Linq olmadan yapmak:

public class Order : IComparable
{
    public DateTime OrderDate { get; set; }
    public int OrderId { get; set; }

    public int CompareTo(object obj)
    {
        Order orderToCompare = obj as Order;
        if (orderToCompare.OrderDate < OrderDate || orderToCompare.OrderId < OrderId)
        {
            return 1;
        }
        if (orderToCompare.OrderDate > OrderDate || orderToCompare.OrderId > OrderId)
        {
            return -1;
        }

        // The orders are equivalent.
        return 0;
    }
}

O zaman Siparişler listenizden .sort ()


3
One zorunluluk ilk test nullüzerinde asdöküm. as(Ha, ha) (Order)objbaşarısız olduğunda bir istisna attığı için bütün mesele budur . if(orderToCompare == null) return 1;.
radarbob

Kodun bakımını kolaylaştıran ve nesnenin yeteneklerini açıkça ortaya koyan arayüzü kullanmak için +1.
AeonOfTime

Bill ve Ted ortaya çıkarsa, beni 16 Ekim 2014'e geri götürmelerini isteyeceğim, böylece yukarıdaki hatamı düzeltebilirim - oyuncu kademesi başarısız olursa asgeri döner null. Ama en azından sıfır testi doğru.
17'de radarbob

@ radarbob evet .. ayy. :) Fakat! Bu işlev otomatik olarak bir liste üzerinde bir sıralama tarafından kullanılmak üzere tasarlanmıştır, List<Order>bu nedenle türün as2014'te eşleşmesi garanti edilmelidir, muhtemelen bir hata yazmadınız, gereksiz bir nöbet ifadesinden kaçınmak kadar :)
Jimmy Hoffa

garanti edilmelidir İlginç bir nokta. İyi bir şekilde kapsüllenmişse, a geçmesi dışında çağrılamaz List<Order>; ama sen ve ben ikimiz de kendi kendine kapsüllenmiş programcı ile tanıştık ki sözde varsayım "bu kodu yazıyorum, bu yüzden yanlış kullanılmayacak"
radarbob

26

Klasik Nesneye Dayalı Bir Çözüm

Öncelikle LINQ'nun muazzamlığına yönelmeliyim .... Şimdi bunu yoldan çıkardık

JimmyHoffa cevabında bir varyasyon. Jenerikler ile CompareToparametre tip güvenli hale gelir.

public class Order : IComparable<Order> {

    public int CompareTo( Order that ) {
        if ( that == null ) return 1;
        if ( this.OrderDate > that.OrderDate) return 1;
        if ( this.OrderDate < that.OrderDate) return -1;
        return 0;
    }
}

// in the client code
// assume myOrders is a populated List<Order>
myOrders.Sort(); 

Bu varsayılan sıralanabilirlik elbette yeniden kullanılabilir. Yani her istemcinin sıralama mantığını gereksiz yere yeniden yazması gerekmez. "1" ve "-1" (veya seçiminiz olan mantık işleçleri) arasında geçiş yapmak sıralama düzenini tersine çevirir.


Bir Listedeki nesneleri sıralamak için basit bir yaklaşım. Ama neden 1 döndürdüğünü anlamıyorum (bu == null)?
Loc Huynh

4
thisnesnenin null değerinden büyük olduğu anlamına gelir . Sıralama amacıyla, boş bir nesne başvurusu "küçüktür" thisnesnesidir. Null'ların nasıl sıralanacağını tanımlamaya karar verdim.
radarbob

18

// Bir gridview ile kullanım için tamamen genel sıralama

public List<T> Sort_List<T>(string sortDirection, string sortExpression, List<T> data)
    {

        List<T> data_sorted = new List<T>();

        if (sortDirection == "Ascending")
        {
            data_sorted = (from n in data
                              orderby GetDynamicSortProperty(n, sortExpression) ascending
                              select n).ToList();
        }
        else if (sortDirection == "Descending")
        {
            data_sorted = (from n in data
                              orderby GetDynamicSortProperty(n, sortExpression) descending
                              select n).ToList();

        }

        return data_sorted;

    }

    public object GetDynamicSortProperty(object item, string propName)
    {
        //Use reflection to get order type
        return item.GetType().GetProperty(propName).GetValue(item, null);
    }

4
Veya, biliyorsun data.OrderBy(). Tekerleği yeniden icat etmek biraz daha kolay.
gunr2171

4
Fikir, bunun her türlü nesne ile çalışacağıdır. OrderBy () yöntemi yalnızca güçlü yazılan nesnelerle çalışır.
roger

1
Benim görüşüme göre, ızgara verileri sıralama en basit ve kullanılabilir çözüm!
kostas ch.

6

Listenin fazladan bir kopyasını oluşturmayan genel bir LINQ uzantısı yöntemi:

public static void Sort<T,U>(this List<T> list, Func<T, U> expression)
    where U : IComparable<U>
{
    list.Sort((x, y) => expression.Invoke(x).CompareTo(expression.Invoke(y)));
}

Kullanmak için:

myList.Sort(x=> x.myProperty);

Yakın zamanda ICompare<U>, karşılaştırmayı özelleştirebilmeniz için bir kabul eden bu eki oluşturdum. Bu bir Doğal dize sıralama yapmak gerektiğinde kullanışlı geldi:

public static void Sort<T, U>(this List<T> list, Func<T, U> expression, IComparer<U> comparer)
    where U : IComparable<U>
{    
    list.Sort((x, y) => comparer.Compare(expression.Invoke(x), expression.Invoke(y)));
}

Bunu uyguladım, iyi çalışıyor. Bir "isAscending = true" parametresi ekledim. Azalan düzende sıralamak için, x ve y öğelerini iki Invoke () yöntemi içinde takas etmeniz yeterlidir. Teşekkürler.
Rob L

Sadece ifadeyi derleyecekseniz, başlamak için bir temsilci kabul etmeniz de mümkündür. Ayrıca, seçici yan etkilere neden oluyorsa, hesaplanması pahalıysa veya deterministik değilse, bu yaklaşımın büyük sorunları vardır. Seçilen bir ifadeye dayalı uygun bir sıralama, seçiciyi listedeki öğe başına en fazla bir kez çağırmalıdır.
14'te

@Servy - bunların hepsi geçerli noktalar, ama dürüst olacağım, bazı önerilerinizi nasıl uygulayacağınızdan emin değilim (özellikle bir seçicinin yan etkilere neden olmasını durdurmak ...?). Onları delege olarak değiştirdim. Bu değişikliklerden bazılarını nasıl yapacağınızı biliyorsanız, kodumu düzenlemekten memnuniyet duyarız.
Peter

3
Sen @Peter olamaz yan etkilere yol açmasını delegeleri engeller. Yapabileceğiniz şey, her nesne için asla bir kereden fazla çağrılmadığından emin olmaktır, bu, her nesne için değerleri hesaplamak, nesneyi / yansıtılan değer çiftlerini saklamak ve ardından sıralamak anlamına gelir . OrderBytüm bunları dahili olarak yapar.
Servise

voidBu ruhla bir uzatma yöntemi yazmanın bir başka güzel yolu : static class Extensions { public static void SortBy<TSource, TKey>(this List<TSource> self, Func<TSource, TKey> keySelector) { self.SortBy(keySelector, Comparer<TKey>.Default); } public static void SortBy<TSource, TKey>(this List<TSource> self, Func<TSource, TKey> keySelector, IComparer<TKey> comparer) { self.Sort((x, y) => comparer.Compare(keySelector(x), keySelector(y))); } }Bir yöntemle desteklenebilir SortByDescending. @ Servy'nin yorumları kodum için de geçerli!
Jeppe Stig Nielsen

4

LINQ kullanma

objListOrder = GetOrderList()
                   .OrderBy(o => o.OrderDate)
                   .ToList();

objListOrder = GetOrderList()
                   .OrderBy(o => o.OrderId)
                   .ToList();

3
//Get data from database, then sort list by staff name:

List<StaffMember> staffList = staffHandler.GetStaffMembers();

var sortedList = from staffmember in staffList
                 orderby staffmember.Name ascending
                 select staffmember;

3

Roger'ın sürümü geliştirildi.

GetDynamicSortProperty ile ilgili sorun sadece özellik adlarını almak ama GridView biz NavigationProperties kullanırsak ne olur? boş olduğu için bir istisna gönderir.

Misal:

"Employee.Company.Name;" çökecektir ... çünkü değerini almak için parametre olarak yalnızca "Ad" a izin verir.

İşte Navigasyon Özelliklerine göre sıralamamızı sağlayan gelişmiş bir sürüm.

public object GetDynamicSortProperty(object item, string propName)
    {
        try
        {                 
            string[] prop = propName.Split('.'); 

            //Use reflection to get order type                   
            int i = 0;                    
            while (i < prop.Count())
            {
                item = item.GetType().GetProperty(prop[i]).GetValue(item, null);
                i++;
            }                     

            return item;
        }
        catch (Exception ex)
        {
            throw ex;
        }


    } 

3

Özellik seçimi hakkında daha genel bir şey yapabilirsiniz, ancak 'Sipariş' durumunuzda seçtiğiniz tür hakkında özel olabilirsiniz:

işlevinizi genel bir işlev olarak yazın:

public List<Order> GetOrderList<T>(IEnumerable<Order> orders, Func<Order, T> propertySelector)
        {
            return (from order in orders
                    orderby propertySelector(order)
                    select order).ToList();
        } 

ve sonra şu şekilde kullanın:

var ordersOrderedByDate = GetOrderList(orders, x => x.OrderDate);

Daha genel olabilir ve sipariş etmek istediğiniz şey için açık bir tür tanımlayabilirsiniz:

public List<T> OrderBy<T,P>(IEnumerable<T> collection, Func<T,P> propertySelector)
        {
            return (from item in collection
                    orderby propertySelector(item)
                    select item).ToList();
        } 

ve aynı şekilde kullanın:

var ordersOrderedByDate = OrderBy(orders, x => x.OrderDate);

Bu, LINQ stili 'OrderBy' yapmanın aptalca gereksiz karmaşık bir yoludur, ancak genel bir şekilde nasıl uygulanabileceğine dair bir ipucu verebilir.


3

Lütfen bazı örnek kodlarla @LukeH tarafından cevabı tamamlamama izin verin, test ettiğim için bazıları için yararlı olabileceğine inanıyorum:

public class Order
{
    public string OrderId { get; set; }
    public DateTime OrderDate { get; set; }
    public int Quantity { get; set; }
    public int Total { get; set; }

    public Order(string orderId, DateTime orderDate, int quantity, int total)
    {
        OrderId = orderId;
        OrderDate = orderDate;
        Quantity = quantity;
        Total = total;
    }
}

public void SampleDataAndTest()
{
    List<Order> objListOrder = new List<Order>();

    objListOrder.Add(new Order("tu me paulo ", Convert.ToDateTime("01/06/2016"), 1, 44));
    objListOrder.Add(new Order("ante laudabas", Convert.ToDateTime("02/05/2016"), 2, 55));
    objListOrder.Add(new Order("ad ordinem ", Convert.ToDateTime("03/04/2016"), 5, 66));
    objListOrder.Add(new Order("collocationem ", Convert.ToDateTime("04/03/2016"), 9, 77));
    objListOrder.Add(new Order("que rerum ac ", Convert.ToDateTime("05/02/2016"), 10, 65));
    objListOrder.Add(new Order("locorum ; cuius", Convert.ToDateTime("06/01/2016"), 1, 343));


    Console.WriteLine("Sort the list by date ascending:");
    objListOrder.Sort((x, y) => x.OrderDate.CompareTo(y.OrderDate));

    foreach (Order o in objListOrder)
        Console.WriteLine("OrderId = " + o.OrderId + " OrderDate = " + o.OrderDate.ToString() + " Quantity = " + o.Quantity + " Total = " + o.Total);

    Console.WriteLine("Sort the list by date descending:");
    objListOrder.Sort((x, y) => y.OrderDate.CompareTo(x.OrderDate));
    foreach (Order o in objListOrder)
        Console.WriteLine("OrderId = " + o.OrderId + " OrderDate = " + o.OrderDate.ToString() + " Quantity = " + o.Quantity + " Total = " + o.Total);

    Console.WriteLine("Sort the list by OrderId ascending:");
    objListOrder.Sort((x, y) => x.OrderId.CompareTo(y.OrderId));
    foreach (Order o in objListOrder)
        Console.WriteLine("OrderId = " + o.OrderId + " OrderDate = " + o.OrderDate.ToString() + " Quantity = " + o.Quantity + " Total = " + o.Total);

    //etc ...
}

3
var obj = db.Items.Where...

var orderBYItemId = obj.OrderByDescending(c => Convert.ToInt32(c.ID));

1

LiNQ ürününü kullanın OrderBy

List<Order> objListOrder=new List<Order> ();
    objListOrder=GetOrderList().OrderBy(o=>o.orderid).ToList();

1

GenericTypeTea'nın Karşılaştırıcısına dayanarak :
sıralama bayrakları ekleyerek daha fazla esneklik elde edebiliriz:

public class MyOrderingClass : IComparer<Order> {  
    public int Compare(Order x, Order y) {  
        int compareDate = x.Date.CompareTo(y.Date);  
        if (compareDate == 0) {  
            int compareOrderId = x.OrderID.CompareTo(y.OrderID);  

            if (OrderIdDescending) {  
                compareOrderId = -compareOrderId;  
            }  
            return compareOrderId;  
        }  

        if (DateDescending) {  
            compareDate = -compareDate;  
        }  
        return compareDate;  
    }  

    public bool DateDescending { get; set; }  
    public bool OrderIdDescending { get; set; }  
}  

Bu senaryoda, sıralama özelliklerini ayarlamak için bunu açıkça MyOrderingClass olarak ( IComparer yerine ) başlatmanız gerekir
:

MyOrderingClass comparer = new MyOrderingClass();  
comparer.DateDescending = ...;  
comparer.OrderIdDescending = ...;  
orderList.Sort(comparer);  

1

Yukarıdaki cevapların hiçbiri benim için yeterince genel değildi, bu yüzden bunu yaptım:

var someUserInputStringValue = "propertyNameOfObject i.e. 'Quantity' or 'Date'";
var SortedData = DataToBeSorted
                   .OrderBy(m => m.GetType()
                                  .GetProperties()
                                  .First(n => 
                                      n.Name == someUserInputStringValue)
                   .GetValue(m, null))
                 .ToList();

Yine de büyük veri setlerine dikkat edin. Bu kolay kod ama koleksiyon çok büyük ve koleksiyon nesne türü çok sayıda alan varsa size sorun olabilir. Çalışma süresi NxM'dir:

N = Koleksiyondaki Eleman Sayısı

M = Nesne İçindeki Özellik Sayısı


1

Null olabilecek türlerle çalışan herkesin Valuekullanılması gerekir CompareTo.

objListOrder.Sort((x, y) => x.YourNullableType.Value.CompareTo(y.YourNullableType.Value));


0

Performans açısından en iyisi, verilerin sonuca eklendikçe sıralanması için sıralı bir liste kullanmaktır. Diğer yaklaşımlar, veriler üzerinde en az bir ek yinelemeye ihtiyaç duyar ve çoğu, yalnızca performans değil, bellek kullanımı da etkilenecek şekilde verilerin bir kopyasını oluşturur. Birkaç yüz elemanla ilgili bir sorun olmayabilir, ancak binlerce ile, özellikle de birçok eşzamanlı isteğin aynı anda sıralanabileceği hizmetlerde olacaktır. System.Collections.Generic ad alanına bir göz atın ve List yerine sıralama içeren bir sınıf seçin.

Mümkün olduğunda yansıma kullanarak genel uygulamalardan kaçının, bu da performans sorunlarına neden olabilir.


Bu nasıl daha performanslı olabilir? Sıralı bir listeye veri eklemek O (n) 'dir, bu nedenle n öğe eklemek O (n ^ 2)' dir. Ne kadar eşzamanlı öğe eklenmeye çalışıyor? Öğeler eklenirken yazdırmak için ekstra CPU döngülerinizin olduğu durumlar vardır, ancak bu iyi bir genel çözüm değildir.
John La Rooy

0

Aşağıdaki kodun olduğunu varsayalım, bu kodda, sıralamak istediğimiz birkaç özelliğe sahip bir Passenger sınıfımız var.

public class Passenger
{
    public string Name { get; }
    public string LastName { get; }
    public string PassportNo { get; }
    public string Nationality { get; }

    public Passenger(string name, string lastName, string passportNo, string nationality)
    {
        this.Name = name;
        this.LastName = lastName;
        this.PassportNo = passportNo;
        this.Nationality = nationality;
    }

    public static int CompareByName(Passenger passenger1, Passenger passenger2)
    {
        return String.Compare(passenger1.Name, passenger2.Name);
    }

    public static int CompareByLastName(Passenger passenger1, Passenger passenger2)
    {
        return String.Compare(passenger1.LastName, passenger2.LastName);
    }

    public static int CompareNationality(Passenger passenger1, Passenger passenger2)
    {
        return String.Compare(passenger1.Nationality, passenger2.Nationality);
    }
}

public class TestPassengerSort
{
    Passenger p1 = new Passenger("Johon", "Floid", "A123456789", "USA");
    Passenger p2 = new Passenger("Jo", "Sina", "A987463215", "UAE");
    Passenger p3 = new Passenger("Ped", "Zoola", "A987855215", "Italy");

    public void SortThem()
    {
        Passenger[] passengers = new Passenger[] { p1, p2, p3 };
        List<Passenger> passengerList = new List<Passenger> { p1, p2, p3 };

        Array.Sort(passengers, Passenger.CompareByName);
        Array.Sort(passengers, Passenger.CompareByLastName);
        Array.Sort(passengers, Passenger.CompareNationality);

        passengerList.Sort(Passenger.CompareByName);
        passengerList.Sort(Passenger.CompareByLastName);
        passengerList.Sort(Passenger.CompareNationality);

    }
}

Böylece sıralama yapınızı Kompozisyon delegesini kullanarak uygulayabilirsiniz.

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.