Czy typ struct można dać jako parametr przy sortowaniu?

0

Czy można w metodzie sortowania jako parametr podać strukturalny typ tablicowy? albo po prostu:jak to zrobić, żeby ten typ był akceptowaly
Chodzi mi o tablice Bibliografia[] tablica = new Bibliografia[10]; Jako parametr w sortowaniu podałem Bibliografia i compilator wyświetla mi taki błąd." 'Bibliografia' cannot be used as type parameter 'T' in the generic type or method Sort<T>'. There is no boxing conversion from 'Bibliografia' to 'System.IComparable'.

 
public struct Bibliografia 
        {
            public string imie;
            public string nazwisko;
            public string informatyk;
            public int isbn;
        }
public class SelectionSort<T> where T :  IComparable
            {
                public T[] Sort(T[] tablica, int n)
                {
                    int k;
                    T temp;

                    for (int i = 0; i < n - 1; i++)
                    {
                        k = i;
                        for (int j = i + 1; j < n; j++)
                        {
                            if (tablica[j].CompareTo(tablica[k]) < 0)
                            {
                                k = j;
                            }
                        }
                        temp = tablica[i];
                        tablica[i] = tablica[k];
                        tablica[k] = temp;
                    }

                    return tablica;

                }
            }
SelectionSort<__**Bibliografia**__> moje_sortowanie = new SelectionSort<__**Bibliografia**__>();
1

Pytanie za sto punktów: Jak chcesz porównać 2 biblioteki i jaki twój problem ma związek z niezaimplementowanym interfejsem do porównywania?

2

Trochę nie tak do tego podchodzisz jak trzeba. Po pierwsze potrzebna jest klasa, która będzie porównywała obiekty typu Bibliografia, a która będzie dziedziczyć interfejs IComparer<Bibliografia>. Obiekt takiej klasy przekazujesz później do metody Sort i masz co chciałeś.

Tutaj masz sortowanie obiektów typu Bibliography po długości łańcucha (takie przykładowe kryterium).

using System;
using System.Collections.Generic;

public class Bibliography {
    public string Name { get; set; }
}

public class BibliographyComparer : IComparer<Bibliography> {
    public int Compare(Bibliography x, Bibliography y) {
        if (x.Name.Length.Equals(y.Name.Length)) return 0;
        if (x.Name.Length < y.Name.Length) return -1;
        return 1;
    }
}

// Algorytmu Ci nie zmieniałem. Zauważ, że metoda `Compare` pochodzi z obiektu `comparer`.
// inaczej metoda nie wiedziałaby po czym ma porównywać obiekty `T`
public class SelectionSort<T> {
    public void Sort(List<T> list, int n, IComparer<T> comparer) {
        int k;
        T temp;
        for (int i = 0; i < n - 1; i++) {
            k = i;
            for (int j = i + 1; j < n; j++) {
                if (comparer.Compare(list[j], list[k]) < 0) {
                    k = j;
                }
            }
            temp = list[i];
            list[i] = list[k];
            list[k] = temp;
        }
    }
}

public class Sorting {
    public static void Main() {
        var list = new List<Bibliography>();
        list.Add(new Bibliography { Name = "Thomasinio" });
        list.Add(new Bibliography { Name = "Adrian" });

        Console.WriteLine(":: Before sort ::");
        list.ForEach(obj => { Console.WriteLine(obj.Name); });


        Console.WriteLine("\n:: After sort ::");
        var ssort = new SelectionSort<Bibliography>();
        ssort.Sort(list, list.Count, new BibliographyComparer());
        list.ForEach(obj => { Console.WriteLine(obj.Name); });
    }
}
I teraz tak:
1. Zamiast struktur używaj klas;
2. Zamiast tablic używaj list, bo są bardziej elastyczne;
3. Przekazując przez argument taką listę nie musisz jej zwracać, bo oryginał jest sortowany;

Inną rzeczą jaką możesz zrobić to zaimplemetować interfejs IComparable<T> w klasie SelectionSort<T> tylko, że ma to swój minus, a mianowicie abstrakcyjność T vide brak dostępu do pól składowcych klasy Bibliography, która w kontekście definicji typu T jeszcze nie istnieje.

0

Grzesiek, dzięki ogromnie za pomoc. Tylko, że ja te wszystkie imiona chce wyświetlić na kontrolce datagridview, a takim przypadku jest potrzebna petla for,bo: dgv.Rows[i].cells[1].value = ob.imie. Niestety efektem twojego rozwiązania jest to, że wyświetla mi 10 razy to samo imie i to w dodatku ostatnie w pozycji.

0

Okej, dobra, już mi wypisuje te imiona, ale specjalnie je wyswietliłem w 4 kolumnie i niestety nie są posortowane. Nie wiem czemu. Muszę to wszystko głębiej przeanalizować.

edit: przez jednego durnego x'a nie sortowało. Już sortuje. Dalej próbuję sam, dzięki, i tak mi bardzo dużo pomogłeś.

1

[Jak kolega jeszcze pokazywał swój kod...]
Na pierwszy rzut oka masz złe warunki. Wiele razy porównujesz obiekt x ze sobą co jest bez sensu. Wszystko da się skrócić:

    public int Compare(Bibliografia x, Bibliografia y) {
        if (x.bs_imie.Length < y.bs_imie.Length && x.bs_nazwisko.Length < y.bs_nazwisko.Length) return -1;
        else if (x.imie.Length.Equals(y.imie.Length) && x.nazwisko.Length.Equals(y.nazwisko.Length) &&
                 x.isbn.Equals(x.isbn) && y.isbn.Equals(y.isbn))
            return 0;
        return 1;
    }

A dodawanie do grid'a na logikę powinno być takie:

for (int i = 0; i<algorytmy_losowania.lista_bibliograficzna.Count; i++){
	grid.Rows.Add();
	grid.Rows[i].Cells[0].Value = i;
	grid.Rows[i].Cells[1].Value = algorytmy_losowania.lista_bibliograficzna[i].Imie;
	grid.Rows[i].Cells[2].Value = algorytmy_losowania.lista_bibliograficzna[i].Nazwisko;
	grid.Rows[i].Cells[3].Value = algorytmy_losowania.lista_bibliograficzna[i].ISBN;
}

http://stackoverflow.com/questions/2397895/how-to-insert-value-into-datagridview-cell

0

Hehe, tylko że ja zrobiłem to trochę inaczej. Wykładowca chce bym robił to na strukturze a nie na klasie, ale twój kod działał nawet i na strukturze.

Oprócz tego, zrobiłem tak, że sklonowałem tablice typu struct do nowej tablicy, żeby użyć ten klon w kodzie obsługującym zdarzenie sortowania i owy klon umieściłem na liście:

lista.AddRange(klon_tablicy);
 

i dziwne, bo wszystko mi wyświetla, ale klon_tablicy zamiast być posortowanym klonem, to jest tablicą z elementami na nowo wylosowanymi. Rozbraja mnie to już.

0

Działanie na strukturze w C# w tym wypadku jest kompletnie bez sensu. Struktura jest typem wartościowym. Ilekroć przekazujesz ją np. jako argument etc... tworzona jest jej kopia! Wykładowca nie wie co robi albo ma nawyk z C++ i uważa, że w pomiędzy strukturą w C#, a w C++ nie ma różnicy. Tak to wygląda.

A klon jest na nowo wylosowanym, bo jest przekazany przez wartość gdyż nie jest typem referencyjnym czyli klasą. Przekazałeś pewnie kopię nieposortowanego zbioru, bo posortowana została kopia oryginalnej struktury! :) Tak na oko masz już ze trzy albo cztery kopie swojej oryginalnej struktury zamiast trzech/czterech kopii referencji do obiektu klasy.

PS: To już drugi czy trzeci przypadek w ciągu kilku dni gdzie ludzie używają struktur zamiast klas w C#. Masakra jakaś.
PS2: Jeżeli już usilnie chcesz używać struktur to przekaż ją przez referencję jawnie za pomocą ref.

0

Przekazałem, ale nie wiem czy dobrze, bo cały czas mi losuje te imiona na nowo. "algorytmy_sortowania" to po prostu klasa.

 
public static Bibliografia[] kopiowanie_istniejacych_tablic(ref Bibliografia[] tab)
            {
                Bibliografia[] klon_tablicy = (Bibliografia[])algorytmy_losowania.tablica_bibliograficzna.Clone();
                return klon_tablicy;
            }
 
Bibliografia[] sklonowana_tablica = new Bibliografia[10];
            sklonowana_tablica = algorytmy_losowania.kopiowanie_istniejacych_tablic(ref algorytmy_losowania.tablica_bibliograficzna);
            
            
            algorytmy_losowania.lista_bibliograficzna.AddRange(sklonowana_tablica);
            algorytmy_losowania.SelectionSort<Bibliografia> moje_sortowanie = new bs_algorytmy_losowania.SelectionSort<Bibliografia>();
            moje_sortowanie.Sort(algorytmy_losowania.lista_bibliograficzna, algorytmy_losowania.lista_bibliograficzna.Count, new algorytmy_losowania());
2

Posłuchaj, to jest do zaorania. Po co Ci tablice w ogóle?

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms; // To musisz dodać poprzez `Add reference`;

public class Bibliography {
    public string Name { get; set; }
    public string ISBN { get; set; }
}

public class BibliographyComparer : IComparer<Bibliography> {
    public int Compare(Bibliography x, Bibliography y) {
        if (x.Name.Length.Equals(y.Name.Length)) return 0;
        if (x.Name.Length < y.Name.Length) return -1;
        return 1;
    }
}

public class SelectionSort<T> {
    public void Sort(List<T> list, int n, IComparer<T> comparer) {
        int k;
        T temp;
        for (int i = 0; i < n - 1; i++) {
            k = i;
            for (int j = i + 1; j < n; j++) {
                if (comparer.Compare(list[j], list[k]) < 0) {
                    k = j;
                }
            }
            temp = list[i];
            list[i] = list[k];
            list[k] = temp;
        }
    }
}

public class Sorting {
    public static void Main() {
        var list = new List<Bibliography>();
        list.Add(new Bibliography { Name = "Thomasinio", ISBN = "12345" });
        list.Add(new Bibliography { Name = "Adrian", ISBN = "67890" });

        var ssort = new SelectionSort<Bibliography>();
        ssort.Sort(list, list.Count, new BibliographyComparer());

        var grid = new DataGridView();
        grid.Columns.Add("lp", "Lp.");
        grid.Columns.Add("imie", "Imię");
        grid.Columns.Add("isbn", "ISBN");

        for (int i = 0; i < list.Count; i++) {
            grid.Rows.Add();
            grid.Rows[i].Cells["lp"].Value = i + 1;
            grid.Rows[i].Cells["imie"].Value = list[i].Name;
            grid.Rows[i].Cells["isbn"].Value = list[i].ISBN;
        }

        var window = new Form();
        window.Width = 800;
        window.Height = 300;
        window.Controls.Add(grid);
        grid.Dock = DockStyle.Fill;
        window.ShowDialog();
    }
}

Jak widzisz lista jest ładnie posortowana. Czemu tak nie możesz zrobić? Jest o niebo prościej.

0

Masz tu alfabetyczny comparer:

public class BibliographyComparer : IComparer<Bibliography> {
    public int Compare(Bibliography x, Bibliography y) {
        if (string.Compare(x.Name,y.Name) == 0) return 0;
        else if (string.Compare(x.Name, y.Name) == -1) return -1;
        return 1;
    }
}

1 użytkowników online, w tym zalogowanych: 0, gości: 1