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

Tomáš Herceg       29. 10. 2011       C#       5876 zobrazení

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--);
}
}
}

 

hodnocení článku

1 bodů / 1 hlasů       Hodnotit mohou jen registrované uživatelé.

 

Nový příspěvek

 

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

Správné řešení je v následujícím blogpostu:

http://vbnet.cz/blog-clanek--400-vyhodno...

nahlásit spamnahlásit spam 0 odpovědětodpovědět

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

Dobře, kód je špatně, protože bude pomalý jestli to dobře chápu. Jak to tedy udělat lépe?

nahlásit spamnahlásit spam 1 / 1 odpovědětodpovědět
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)

nahlásit spamnahlásit spam 0 odpovědětodpovědět

i-- se spustí až po tom RemoveAt, takže v tom problém není.

nahlásit spamnahlásit spam 0 odpovědětodpovědět

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

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?

nahlásit spamnahlásit spam 0 odpovědětodpovědět

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.

nahlásit spamnahlásit spam 0 odpovědětodpovědět

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.

nahlásit spamnahlásit spam 0 odpovědětodpovědět

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.

nahlásit spamnahlásit spam 0 odpovědětodpovědět

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.

nahlásit spamnahlásit spam 0 odpovědětodpovědět
                       
Nadpis:
Antispam: Komu se občas házejí perly?
Příspěvek bude publikován pod identitou   anonym.

Nyní zakládáte pod článkem nové diskusní vlákno.
Pokud chcete reagovat na jiný příspěvek, klikněte na tlačítko "Odpovědět" u některého diskusního příspěvku.

Nyní odpovídáte na příspěvek pod článkem. Nebo chcete raději založit nové vlákno?

 

  • Administrátoři si vyhrazují právo komentáře upravovat či mazat bez udání důvodu.
    Mazány budou zejména komentáře obsahující vulgarity nebo porušující pravidla publikování.
  • Pokud nejste zaregistrováni, Vaše IP adresa bude zveřejněna. Pokud s tímto nesouhlasíte, příspěvek neodesílejte.

přihlásit pomocí externího účtu

přihlásit pomocí jména a hesla

Uživatel:  
Heslo:  

zapomenuté heslo

 

založit nový uživatelský účet

zaregistrujte se

 
zavřít

Nahlásit spam

Opravdu chcete tento příspěvek nahlásit pro porušování pravidel fóra?

Nahlásit Zrušit

Chyba

zavřít

feedback