[OOP] Defining Classes Part Two - Задача 5, 6, 7


7
5.Write a generic class GenericList<T> that keeps a list of elements of some parametric type T. Keep the elements of the list in an array with fixed capacity which is given as parameter in the class constructor. Implement methods for adding element, accessing element by index, removing element by index, inserting element at given position, clearing the list, finding element by its value and ToString(). Check all input parameters to avoid accessing elements at invalid positions.
 
6.Implement auto-grow functionality: when the internal array is full, create a new array of double size and move all elements to it.
 
7.Create generic methods Min<T>() and Max<T>() for finding the minimal and maximal element in the  GenericList<T>. You may need to add a generic constraints for the type T.
 
Решение+patch1: http://pastebin.com/D9yCXqfC
В count съхранявам кой по ред елемент записвам в масива.
 
В метода Delete(T point), не можах да измисля как да взема индекса на елемента, който се подава testList[1] с идекс, и затова използвам Array.IndexOf което не е много правилно, защото ако имам еднакви елементи ...
 
В метода InsertElement(int position, T element) ако масива ми е пълен ще загубя последния елемент.
 
С метода StretchCapacity() удвоявам дължината на масива.
 
За седма задача добавям интерфейса IComparable
 
public class GenericList<T>
    where T : IComparable
 
 



Отговори



3
http://pastebin.com/D5tn1Prt
Ей това е от мен.При Delete намалям counta, а при Insert го увеличавам.Не съм наясно доколко е вярно.Трябва някой опитен да се включи и да издаде някоя-друга хитрина :)

от Diagara (277 точки)


0

Може и без цикъл:

public void Delete(T point)
{
    int index = Array.IndexOf(elements, point);
    if(index < 0)
        return;
 
    var tempArray = new T[elements.Length - 1];
    Array.Copy(elements, 0, tempArray, 0, index);
    Array.Copy(elements, index + 1, tempArray, index, (elements.Length - 1 - index));
    elements = tempArray;
}



0
и аз мислях така да го направя, но се намалява дължината на масива с 1, а нали е фиксирана


0
Здравей, Имам и аз един въпроса и предложение... Първо - метода ти по-скоро трябва да приема индекс като параметър, а не елемент, защото в условието се иска да се трие по индекс (но това не е толкова важно :D). Въпроса ми е: ако не искаме да създаваме нов масив (в твоя случай tempArray), а направо да копираме в същия масив, т.е. Array.Copy(elements, index+1 , elements, index, elements.Length-1 - index) , какво да правим с последния елемент, които остава в elements? Ако се опитам да кажа elements[Length-1] = null; компилатора се оплаква, че не може T да е null. С други думи- какво трябва да го правя този последен елемент и трябва ли наистина да правя нов масив за да избегна това?

от Subo_Rusev (1389 точки)



0

http://pastebin.com/EpF0cxjH 

Не е завършен напълно още класа, но съм направил повечето методи. Като за DeleteAt и InsertAt копирам масива само веднъж:

Array.Copy(this.list, position + 1, this.list, position, this.index - position);

При InsertAt проверам дали масива не е пълен. Ако е пълен първо правя нов и тогава вкарвам елемента.Така няма да се загубят елементи.

 


от Божидар Пенчев (0 точки)


0
това с Array.Copy в същия масив е много хитро, не знаех че може така пускам първия patch :)


0
Аз питах и Цветомир Николов, но сега видях, че и ти се опитваш да правиш същото като мен. Така както си го направил сега последният ти елемент си остава, а трябва да го изтрием по някакъв начин. Въпроса е как да го направим без да правим нов масив, ами да е в същия?

от Subo_Rusev (1389 точки)



3

Колеги здравейте. Условието на задачата по която имам въпрос:

 

7.Create generic methods Min<T>() and Max<T>() for finding the minimal and maximal element in the  GenericList<T>. You may need to add a generic constraints for the type T.

Искам да ви попитам дали следния метод e legit:

 

    public T Min<T>()
        {
            T min= (T)(object)arr.Min();
            return min;
        }
Бачка си, но този каст ми изглежда на мега хака :D
Дайте съвет как се прави по-готино ;)
 

Edit: Ето и целия source на class GenericList<T>


от ivivanov (903 точки)


0
Здравей. Аз подходих така: на целия клас направих Т да е IComparable. А метода ми е следния: public T Min() { T minValue = this.list[0]; for (int i = 0; i < this.index; i++) { if (this.list[i].CompareTo(minValue) < 0) { minValue = this.list[i]; } }
return minValue; } Но не съм сигурен дали това е най-правилния начин.

от Божидар Пенчев (0 точки)

0
аз го правя без кастване public T Min() { return elements.Min(); }




1

И от мен нещо: https://github.com/martinivanovit/Telerik-Academy-Repo/blob/master/Homeworks/CSharp/OOP/GenericList.cs

За сега една от най-интересните задачи.. за мен поне.
При добавянето, вмъкването и изтриването на елемент използвам брояч, за да  следя размера на колекция, останалата част от нея (докато се достигне капацитета) е запълнена с нули.

Ако излезем извън размера ще достъпим някоя от тези нули, които се води, че не са част от листа за това, когато стане метода хвърля изключение.

Когато достигнем капацитета на колекцита го увеличаваме двойно.

Чистенето на масива става, като го създадем наново и занулим брояча за дължината.

Търсенето на позицията на даден елемент се държи, като IndexOf.. ако не намери нищо връща -1


от Mahata231 (1351 точки)


0
Това dynamic мисля, че ще забавя обектите от този клас. ;) Разбира се, това е твоя клас и можеш да го реализираш както искаш. :)

от vlad_karamfilov (4595 точки)

0
в последните 3 метода ли? Без него не иска да ми сравнява елементите. Не знам как да го направя иначе

от Mahata231 (1351 точки)



15

Който иска да види как програмистите на Microsoft биха написали домашното му, може да отвори JustDecompile (free tool на Telerik) и да намери сорса на класа List<T> в System.Collections.Generic:

Разбира се, хубаво е човек първо сам да си напише класа и после да разгледа и този вариант, защото може да научи някой и друг трик за работа с масиви например.

Относно методите Min и Max, ами може като членове на GenericList да се направят или като външни, които приемат GenericList<T> като параметър.

Ако решим да са вътрешни, не е добра идея заради тях да слагаме ограничение за Т: IComparable<T>. Стандартният List<T> не налага такива ограничения. Т.е. в метода public T GenericList<T>.Min() {...} можем да направим нещо от рода на:

 


if (this.items[0] is IComparable<T>)
        {
            T min = this.items[0];
 
            for (int i = 1; i < this.size; i++)
            {
                if ((min as IComparable<T>).CompareTo(this.items[i]) > 0)
                {
                    min = this.items[i];
                }
            }
 
            return min;
        }
        else
        {
            throw new ArgumentException("At least one object must implement IComparable.");
        }
 
Хвърляме Exception, ако елементите на списъка не могат да се сравняват - потребителят сам си носи отговорност, ако търси минималния от несравними елементи. Всъщност ако списъкът има единствен елемент, можем да върнем него (дори и да не е IComparable), няма нужда от Exception, защото и без това няма с кого да го сравняваме.
 
Ето целия вариант (cannibalized версия на List<T> с Min() и Max() и тестов клас с външни Min() и Max()):

от vic.alexiev (2299 точки)


0
Ако си направиш класа да ти наследява интерфейса IComparable няма смисъл да се пробваш да кастваш към него само в мин метода. Според мен щом имаш метод, който изисква такъв интерфейс, по-добре целия клас да работи само с типове, които го поддържат.

от AsenVal (3487 точки)

0
Съгласен съм с vlad_karamfilov, че е най-елегантно Min() и Max() да са extension методи. Всъщност и Microsoft така са решили проблема с техния List

от vic.alexiev (2299 точки)



3

Лично за мен най-интересната задача от класове до сега :)

Това е решението ми!

Почти всички методи съм ги писал доста обяснително..с цикли. Като разглеждах другите решенията видях, че има доста по олекотени решения, но реших да си я направя по дългия начин.

Малко разяснения: ( за тези неща, които биха са по особени)

Когато премахвам елемент (DeleteElement) записвам в един нов масив всички остаанали елемент без този, който махаме с помоща на два цикала от 0 до този , който махаме и от него +1 до count. Накрая копирам новия масив в стария и увеличавам count  с 1.

Когато вкарвам елемент на опр. позиция правя същото, само, че въвеждам новия елемент между двата цикъла.

Когато изчислвам листа,викам DeleteElements толкова пъти колкото елемента имам в масива. :)

 


от boncho.vylkov (1923 точки)


0
Не си имплементирал индексатора коректно, трябва да стане нещо подобно:
public T this[int index] { get { return list[index]; }
set { list[index] = value; } }

от Teodor92 (13062 точки)

0
Ще го оправя. Благодаря :)

от boncho.vylkov (1923 точки)



2

Това ми беше една от най интересните домашни до сега.

https://github.com/KrisNickson/CSharp-Random-Stuff/tree/master/GenericListStuff

Това е моето решение, няма смисъл да го обяснявам тук - кода е пълен с описателни коментари. Все пак ако имате някакви въпроси или коментари, стреляйте, дет се вика.

Едит: иправих корав бъг дето бях пропуснал да оправя, ако някой вече е свалил, да свали пак.


от KrisNickson (2635 точки)


12
Тайната на методите Min

от vlad_karamfilov (4595 точки)


0
Ако на самия клас дадеш :IComparable

от KrisNickson (2635 точки)

0
Точно така го бях направил, но след известно време търсене попаднах на това, което ми трябваше и реших да го споделя с вас. :) Мисля, че това е най-правилния начин. :)

от vlad_karamfilov (4595 точки)



0

Искрени благодарности на колегата Виктор, от когото мазно мазно свих "..as IComparable<T>" , без което методите ми за мин и макс стояха грозно.

Иначе моята имлементация на решението на изискваните проблеми е разбираемо за четене (откровено си казвам, че може да изпуснал някоя проверка за достоверност на данните).

https://github.com/Bvaptsarov/Homework/tree/master/10.OOPSecondPart/GenericList


от Prophian (1234 точки)