Vývojářský blog Tomáše Hercega

Tisk článku Tisk článku

Hádanka: Odstranění více položek ze seznamu

[Zpět na blog]

Datum: 29. 10. 2011 21:58       Autor: Tomáš Herceg       Zobrazeno: 703x

Kategorie: C#


Nedávno na Twitteru Tomáš Slavíček narazil na to, že v .NET Frameworku na Windows Phone 7 nemá třída List metodu RemoveIf. Tato metoda na vstupu dostane jako parametr funkci, která bere jeden prvek seznamu a vrací boolean. Prvky, pro které tato funkce vrátí true, se ze seznamu smažou.

Tuhle funkci pak použil ve svém výborném článku Vyvíjíme pro WP v XNA: Vykreslení, výběr a pohyb objektů.

Následující implementace funkce RemoveIf má ale jednu drobnou vadu. Pro účely toho článku to vůbec nevadí, ba právě naopak – nemá smysl vysvětlovanou problematiku komplikovat něčím takovým, je lepší začátečníkům naservírovat kód, který je krátký a srozumitelný.

Na druhou stranu – najdete problém, který toto řešení má?

 using System;
using System.Collections.Generic;
using System.Linq;

namespace SmartmaniaHra
{
public static class ExtensionMethods
{
public static void RemoveIf<T>(this List<T> list, Func<T, bool> predicate)
{
for (int i = 0; i < list.Count; i++)
if (predicate(list[i]))
list.RemoveAt(i--);
}
}
}

> Na začátek

 

Hodnocení:

Hlasů: 1
Zvolte své hodnocení

Tomáš Herceg

Jsem hlavním softwarovým architektem ve společnosti Riganti. Mám dlouholeté zkušenosti s technologiemi ASP.NET, Silverlight, WPF a XNA. Působím též jako lektor ve společnosti Gopas a již třetím rokem jsem držitelem ocenění Microsoft Most Valuable Professional.

Podpořte vznik dalších článků
RSS Feed RSS Feed

Diskuse

1 

:)

Datum: 29.10.2011 23:03
Autor: neregistrovaný (213.192.0.30)
Hodnocení autora: není
Příspěvků: 0
Nechtěl bych tou extension metodou mazat celý seznam. Tomáš Slavíček dokonce má v jedné větě řečeno, jak opravit tenhle problém bez změny struktury řešení, ale v úplně jiném kontextu. Tomáši víš o tom, že jsi na tuhle hádanku už odpověděls na twitteru?
 
           [Odpovědět]
 
Hodnocení: 0 Čekejte, prosím...

Re: :)

Datum: 29.10.2011 23:38
Autor: Tomáš Herceg
Hodnocení autora: 1685
Příspěvků: 3558
Však na tom taky není nic světoborného a zkušené oko to vidí na první pohled. Ale ne každý Twitter sleduje.
 
           [Odpovědět]
 
Hodnocení: 0 Čekejte, prosím...

Re: :)

Datum: 30.10.2011 0:40
Autor: neregistrovaný (213.192.0.30)
Hodnocení autora: není
Příspěvků: 0
Fuj, stydím se, co jsem to napsal za blbbost. V původním článku není naznačeno, jak ten kód upravit tak, aby fungoval bez problému. Měl bych se konečně naučit číst.

 
           [Odpovědět]
 
Hodnocení: 0 Čekejte, prosím...

Re: :)

Datum: 30.10.2011 8:54
Autor: Tomáš Slavíček
Hodnocení autora: 10
Příspěvků: 46
Ano, nakonec jsem se také nachytal a do článku to zjednodušil až moc :) Pro tento případ to ale naštěstí vůbec nevadí. Jinak ta metoda na velkém .NET Frameworku se jmenuje RemoveAll() (také asi nemá ideální implementaci), tady jsem raději zvolil jiný název, abych zatím čtenáře nemusel zatěžovat ifdefy apod., pokud by si chtěli hru portovat na PC.
 
           [Odpovědět]
 
Hodnocení: 0 Čekejte, prosím...

Re: :)

Datum: 30.10.2011 9:01
Autor: Tomáš Herceg
Hodnocení autora: 1685
Příspěvků: 3558
Ve velkém .NET Frameworku se metoda skutečně jmenuje RemoveAll, není sice napsaná úplně nejpřehledněji, ale v kontextu toho, co zde řešíme, je napsaná správně.

Btw. Ifdefy by nutné nebyly, pokud existuje na třídě metoda s takovými parametry, extension metoda se automaticky ignoruje.
 
           [Odpovědět]
 
Hodnocení: 0 Čekejte, prosím...

Jak to udělat lépe?

Datum: 1.11.2011 8:50
Autor: neregistrovaný (82.99.185.6)
Hodnocení autora: není
Příspěvků: 0
Dobře, kód je špatně, protože bude pomalý jestli to dobře chápu. Jak to tedy udělat lépe?
 
           [Odpovědět]
 
Hodnocení: 1 Čekejte, prosím...

Re: Jak to udělat lépe?

Datum: 3.11.2011 13:19
Autor: neregistrovaný (147.32.228.51)
Hodnocení autora: není
Příspěvků: 0

using System;
 using System.Collections.Generic;
 using System.Linq;
 
 namespace SmartmaniaHra
 {
     public static class ExtensionMethods
     {
         public static void RemoveIf<T>(this List<T> list, Func<T, bool> predicate)
         {
             for (int i = 0; i < list.Count; i++)
                 if (predicate(list[i]))
                     list.RemoveAt(i--);
         }
     }
 }
 

Seznamy se indexují od 0. Pokud hned první prvek v seznamu splní podmínku (bude true) a index i se sníží o jednu, bude se i rovnat -1 a dojde k vyhození vyjímky. Tento kód nebude mazat prvek pro který je platná podmínka, ale vždy prvek před ním (nemožnost smazat poslední prvek v seznamu). Podle mě stačí jen tato úprava:

list.RemoveAt(i)
 
 
           [Odpovědět]
 
Hodnocení: 0 Čekejte, prosím...

Re: Jak to udělat lépe?

Datum: 3.11.2011 13:41
Autor: Tomáš Herceg
Hodnocení autora: 1685
Příspěvků: 3558
i-- se spustí až po tom RemoveAt, takže v tom problém není.
 
           [Odpovědět]
 
Hodnocení: 0 Čekejte, prosím...

Správné řešení

Datum: 3.11.2011 14:44
Autor: Tomáš Herceg
Hodnocení autora: 1685
Příspěvků: 3558
Správné řešení je v následujícím blogpostu:

http://vbnet.cz/blog-clanek--400-vyhodno...
 
           [Odpovědět]
 
Hodnocení: 0 Čekejte, prosím...
1 
 

VBNET.CZ | © 2007 Tomáš Herceg, Tomáš Jecha | Kopírování a přejímání jakéhokoliv obsahu z tohoto webu je bez písemného svolení autorů zakázáno.