niedziela, 30 grudnia 2012

Konwersja z bmp na jpeg w PowerShell

Kiedy masz dużo plików graficznych w bmp, warto jest zastanowić się nad zmiana formatu na jpeg. Pliki mają mniejszy rozmiar, a nie tracą tak bardzo na kompresji. Napisałem skrypt do konwertowania plików z jednego formatu na drugi. Wystarczy w kodzie wyselekcjonować pliki, które są bmp i w potoku wpisać nazwę funkcji:
gci -filter *.bmp | Convert-Jpeg

Poniżej cała implementacja funkcji zamieniająca bmp na jpeg:
[Reflection.Assembly]::LoadWithPartialName("System.Drawing") | Out-Null

function Convert-Jpeg {
[CmdletBinding()]
Param(
     [Parameter(Mandatory=$True,ValueFromPipeline=$True,ValueFromPipelinebyPropertyName=$True)] 
     [System.io.FileInfo] $filepath
)

BEGIN {
     Write-Host "Converting Bitmaps to Jpegs" 
     $fileConvertedCounter= 0
}

PROCESS{
        $filePathFullName = $filepath.FullName
        if( Test-Path $filePathFullName)
        {
            $image  = [System.Drawing.Image]::FromFile($filepath.FullName)
            $bitmap = new-object System.Drawing.Bitmap($image)
            $newFileName = ($filePathFullName -replace '([^.]).bmp','$1') + ".jpg"
            $bitmap.Save($newFileName, ([system.drawing.imaging.imageformat]::jpeg))
            $fileConvertedCounter++
            Write-Host "Converted $filePathFullName into $newFileName"
            $bitmap.Dispose()
            $image.Dispose()        
        }else {
            Write-Host "Path not found."
        }
}

END{
    Write-Host "It was $fileConvertedCounter converted files" 
}

}

Ugly strings

Mam super pomysł jak ograniczyć pisanie kodu z duża ilością rozrzuconych tekstów. Wystarczy ustawić kolor czcionki w tekst edytorze na string tak, aby od razu tekst rzucał się w oczy :)


Efekt takiej zmiany wygląda okropnie :)



Taka czcionka wymusza na użytkowniku tworzenie regionów ze stałymi stringami w jednym miejscu albo wydzielenie tego tekstu do osobnego zasobu (klasy albo resourca).


sobota, 29 grudnia 2012

Kopiowania kodu bez svn

Jeżeli masz kod źródłowy, który jest podpięty pod system kontroli wersji (svn) to ciężko jest skopiować tylko sam kod bez plików do kontroli wersji. Za pomocą PowerShell można to osiągnąć znacznie szybciej niż ręcznie wykonując kopiowanie .
function Copy-File-Exclude-Svn {
Param(
    [string] $sourceLocation=".",
    [string] $destinationClocation=".\No_SVN"
)
$files = gci -force  -exclude *.svn-base,".svn",".gitignore"  $sourceLocation  | ? {  $_.PSIsContainer -and $_.Length -lt 230 } | gci -recurse

$files | foreach {
        $fileEnding = $_.FullName.Replace($sourceLocation, "");
        $firstItem = $_.FullName;
        $secondItem = $destinationClocation  + $fileEnding ;
        Write-Host "Copy from $firstItem to $secondItem";
        Copy-Item $firstItem $secondItem;
    }
}


Wywołanie kopiowania plików wygląda następująco:
Copy-File-Exclude-Svn 
-sourceLocation "C:\Source\Project1" 
-destinationClocation ""C:\Source\Project1_without_svn"


niedziela, 16 grudnia 2012

Dokument w prezentacji

--Co się stanie jak połączysz dokument tekstowy ze slajdem w swojej prezentacji??
--Powstanie SlideUment :D
Taki suchar.

Zapewne zapytasz co to takiego. Pozwól, że przybliżę ci ten problem. Siedzisz na prezentacji w ostatnim rzędzie. Prowadzący zaczyna mówić ciekawie, więc jesteś zainteresowany prezentacją. Wszystko jest ok, aż w pewnym momencie prezenter przełącza na nowy slajd, a w twoich oczach pojawia się 'wielki' dokument mówiący o wszystkich najważniejszych rzeczach, ale kompletnie nieczytelnie dla ciebie. Mnie w takich momentach ogarnia frustracja i więcej nie chce uczestniczyć w takich prezentacji.

Poniżej przedstawiam 3 przykładowe slideumenty:


Słowo Slideument oznacza dokument przedstawiony w formie slidu w prezentacji (postać hybrydy). Pojęcie to zostało opisane przez Garr Reynolds na stronie Presentation Zen. Dokument i prezentacja mają inne cele, dlatego powinny one być inaczej przedstawione.

Nie jestem specjalistą od dekompozycji prezentacji, ale jeżeli mógłbym ci doradzić w uniknięciu slideumentu to po prostu przedstaw najważniejsze kwestie i zamieść odnośnik do dokumentu na końcu prezentacji. Oprócz tego możesz też rozdzielić cały slideument na klika lepiej przedstawionych slidów.


piątek, 14 grudnia 2012

Dobre filmy

Czy kiedykolwiek zdarzyło ci się, że oglądałeś film w kinie, na który polecił ci kolega lub trailer był fajny i po parunastu minutach (nie liczę czasu z reklamami przed filmem) okazało się, że jest to kompletny badziew. Ja wtedy siedzę spokojnie i mówię do sobie, że „już zapłaciłem i poświeciłem czas na dojazd do kino, to jeszcze tą godzinę wytrzymam”. Jeżeli miałeś taką sytuacje jak ja, to może ci pomóc mechanizmu zaimplementowany na portalu filmweb. Teraz oglądam te dobre filmy, wygenerowane z rekomendacji.



Ale jakie są dobre, a jakie słabe filmy? Każda osoba ma swój własny gust filmów. Mechanizmem do wyliczania scoringu filmu nazywa się Gustomierz. Korzysta z wielu zmiennych, takich jak gatunek, głosy innych użytkowników czy twórcy filmu. Model do wyliczenia najlepszych filmów działa na bazie algorytmu K-najbliższych sąsiadów.
I pamiętaj. Szanuj swój czas jaki poświęcasz na oglądanie filmów.

czwartek, 13 grudnia 2012

Achievements w Visual Studio

Gry, aby były bardziej atrakcyjniejsze dla gracza, wprowadziło się termin achievementy, czyli osiągnięcia. Za każdą wykonaną specjalną rzecz, odblokowuje się pewne osiągnięcie. Później taki gracz może pochwalić się takim osiągnięciem przed kolegami czy na Facebooku. Osiągnięcia mają już minecraft, WoW czy Team Fortress (razem ze statystyką osiągnięć ). Możesz też zdobywać osiągnięcia na XBox360. Mimo tego, że kilka lat temu każdy potępiał ten pomysł, dziś dla większości graczy stanowią nieodłączną część zabawy. Do tego stopnia, że niektórzy z nich katują godzinami tytuły, na które nigdy by nawet nie spojrzeli, a wszystko po to, aby być na wyższym poziomie w rankingu.

Takie osiągnięcia są też dla Visual Studio. Powstał specjalny plugin do VS. Tak jak w grach komputerowych, za wykonaną czynność dostajemy osiągnięcie. VS Achievements nie tylko bawi, ale również uczy. Wykonując pewne osiągnięcia, możesz się nauczyć pewnych narzędzi, technologii czy sposobów pisania kodu. Jest tez ranking użytkowników VS.



Achievementy w grach wprowadzono po to, aby w prosty sposób mogły wydłużyć spędzanie czasu wolnego przed grą i zwiększyły więzi między graczem a grą. To samo dzieje się z VS. Dodatek do VS2012 można pobrać tutaj.

Nie mam wielkich osiągnięć, ale raz na jakiś czas będę się starał, aby wykonać jakieś 'głupie' osiągnięcie. Poniżej jest moja statystyka.

środa, 12 grudnia 2012

Problem rozwiązany przez czas

Wszyscy mówią, aby 'nie odkładać rozwiązania problemu na później', 'to co masz zrobić jutro, spróbuj zrobić dzisiaj' itd. Ja sam nie jestem specialistą od prokrastynacji, ale mam swoją metodę na rozwiązywanie problemów, a dokładnie na ich odkładanie. Nie staraj się od razu rozwiązać jakiś problem, ale ustal czy ten problem jest nieszkodliwy i niepilny. Mogą być problemy, które są nieszkodliwe i pilne (np. spóźnienie się na zajęcia, rozmowa telefoniczna z trudnym klientem), ale również mogą być szkodliwe i niepilne (np. problem w relacjach ze znajomymi, odkładanie na emeryturę). Jeżeli twój problem jest nieszkodliwy i niepilny to ustal jego ramy czasowe. Ustal do kiedy chcesz rozwiązać ten problem. Pamiętaj o tym, że każde rozwiązanie potrzebuje trochę czasu na realizację. Zapisz sobie ten problem i po jakimś czasie spróbuj powrócić do niego. Takie odkładanie problemów może spowodować, że te problemy same się rozwiążą. Czasami nie warto zamęczać się rozważaniami nad rozwiązaniem problemu. Czasami jest tak, że dany problem zostanie rozwiązany przez kogoś innego. Może się zdarzyć, że ten problem zostanie zastąpiony szkodliwszym problemem, a wtedy ten wcześniejszy przestanie istnieć.

Klasyfikowanie problemów ze względu na szkodliwość i pilność ma dużo wspólnego z macierzą Eisenhowera. Macierz(matryca) Eisenhower'a (Eisenhower matrix) można też nazywać Systemem Eisenhower’a (Eisenhower system), Siatką Eisenhower’a (Eisenhower grid), Polami Eisenhower’a (Eisenhower boxes) lub Kwadrat Eisenhower’a (Eisenhower square). Najważniejszą cechą macierzy jest pomoc w ustalaniu priorytetów w działaniach. Każdy cel, zadanie i czynność można nanieść na odpowiednią ćwiartkę.



Interpretacja macierzy jest następująca:
Ćwiartka I: rzeczy ważne i również pilne, które powinniśmy zrealizować sami lub delegować dla innych ( w natłoku innych spraw). W tej ćwiartce to zazwyczaj sytuacje nagłe, trudne do przewidzenia, lub skutki zaniedbania i niewykonywania regularnej pracy oraz sytuacje kryzysowe.

Ćwiartka II: rzeczy ważne, ale niepilne, które możemy rozłożyć w czasie lub wykonywać regularnie. Czynności, które mogłyby się znaleźć w tej części to: rekreacja, szkolenia, ćwiczenia fizyczne, przygotowania do projektu, regularna praca nad sobą.

Ćwiartka III: rzeczy pilne, jednak mało ważne – powinniśmy wykonać lub zlecić w drugiej kolejności, zaraz po zadaniach z części A. Czynności z tego obszaru nie są istotne lecz wymagają jak najszybszego wykonania, możemy do nich zaliczyć np. uregulowanie rachunków, rozmowa telefoniczna lub wizytę u znajomych

Ćwiartka IV: rzeczy mało ważne i mało pilne – po prostu możesz te rzeczy olewać. Najlepszym miejscem dla czynności z tej części jest kosz. Nie są one dla nas istotne. Zazwyczaj to one są tzw. pożeraczami czasu. Przykłady tej czynności to bezcelowe patrzenie w TV podczas nudnego programu. Zadania z tej ćwiartki można bez problemu przesunąć na dalszy plan. Odkładanie problemu nieszkodliwego i niepilnego należy do 4 ćwiartki.

Oczywiście trudno jest nakreślić uniwersalny schemat postępowania dla wszystkich ponieważ, wszystko jest uzależnione od naszych prywatnych preferencji.

Jak przyspieszyć kodowanie cz.4 (testy sparametryzowane)

To, co mi się najbardziej podoba w NUnit to 'sparametryzowane testy'. Najlepiej na przykładzie będę mógł pokazać ci piękno tego rozwiązania. Dajmy na to, że mamy klasę z 'skomplikowaną' logiką.
public class Sum
{
 public int Value1 { get; set; }
 public int Value2 { get; set; }

 public int Result
 {
    get { return Value1 + Value2; }
 }
}
Klasa Sum w polu Result zwraca sumę pól Value1 i Value2. Użycie tej klasy wygląda następująco:
var sum =  new Sum { Value1 = value1, Value2 = value2 };
sum.Result;
Stwórzmy do niego test sprawdzający działanie przykładowych liczb, dodawanie elementu neutralnego (zero) oraz dodawanie liczby przeciwnej.
        [Test]
        public void It_should_return_sum_3()
        {
            int value1 = 1;
            int value2 = 2;
            var sum = new Sum { Value1 = value1, Value2 = value2 };
            Assert.AreEqual(3, sum.Result);
        }

        [Test]
        public void It_should_return_0_because_number_of_opposing()
        {
            int value1 = 1;
            int value2 = -1;
            var sum = new Sum { Value1 = value1, Value2 = value2 };
            Assert.AreEqual(0, sum.Result);
        }

        [Test]
        public void It_should_return_0_because_adding_neutral_nuber()
        {
            int value1 = 2;
            int value2 = 0;
            var sum = new Sum { Value1 = value1, Value2 = value2 };
            Assert.AreEqual(2, sum.Result);
        }
Mamy 3 metody, które testują 3 różne przypadki. Od razu widać, że kod się powtarza, więc chcemy zredukować powtarzający się kod w tych testach. Możemy zastosować atrybut TestCase. W tym atrybucie podajemy wartości obiektów z jakimi ma być wywołana metoda. Przykład jest poniżej:
        [TestCase(1, 2, 3)]
        [TestCase(2, 0, 2)]
        [TestCase(1, -1, 0, TestName = "Because number of opposing")]
        public void It_should_return_sum(int value1, int value2, int expected)
        {
            var sum = new Sum { Value1 = value1, Value2 = value2 };
            Assert.AreEqual(expected, sum.Result);
        }
Dokładnie to mi się najbardziej podoba w NUnit. Mamy przetestowane 3 różne przypadki użycia i napisało się tylko jedną metodę. W tej metodzie 2 pierwsze argumenty atrybutu są jako dane wejściowe naszej operacji, a 3 argument jest jako wynik tej operacji. Dla poszczególnych przypadków testowych (TestCase), można jeszcze określić nazwę testu, opis, jaki wyjątek ma być wyrzucony oraz jaka wartość ma być zwracana przez tą metody. Możemy wykorzystać ten ostatni parametr.

        [TestCase(1, 2, Result = 3)]
        [TestCase(1, -1, Result = 0, TestName = "It should return 0")]
        [TestCase(2, 0, Result = 2, TestName = "Adding zero")]
        public int It_should_return_sum2(int value1, int value2)
        {
            var sum = new Sum { Value1 = value1, Value2 = value2 };
            return sum.Result;
        }
Przekształcenie bardzo przypomina 'normalną' (bez aserci) metodę, ale z atrybutami. Mam diaboliczny pomysł. Parametr Result możemy dodać do normalnej metod statycznej. W taki sposób można mieć kod implementacyjny i testy w jednym projekcie - it's crazy.

    public class SumFactory
    {
        [TestCase(1, 2,  Result = 3)]
        [TestCase(1, -1, Result = 0, TestName = "It should return 0")]
        [TestCase(2, 0,  Result = 2, TestName = "Adding zero")]
        public int Sum(int value1, int value2)
        {
            return value1 + value2;
        }
    }
To jest pierwszy przykład jak możemy wykorzystać TestCase - drugi przykład jest dla TestFixture. Napiszmy generyczną klasę, która będzie dodać 2 zmienne:

    public class GenericSum<T>
    {
        public T Value1 { get; set; }
        public T Value2 { get; set; }

        public T SumValue
        {
            get { return (dynamic)Value1 + (dynamic)Value2; }
        }
    }
I chcielibyśmy przetestować dodawanie domyślnych wartości dla zmiennych typu int i double.
    [TestFixture(typeof(int))]
    [TestFixture(typeof(double))]
    public class GenericTestNUnit<T>
    {
        [Test]
        public void It_should_return_default_value()
        {
            var sum = new GenericSum<T> { Value1 = default(T), Value2 = default(T)};
            Assert.AreEqual(default(T), sum.SumValue);
        }
    }
Argument w atrybucie TestFixture odnosi się do typu T. Takie sparametryzowane testy mają zastosowanie w testowaniu klas dziedziczących.

    public abstract class AsBiOperation
    {
        public int Value1 { get; set; }
        public int Value2 { get; set; }
        public abstract int Result { get; }
    }
    public class SumOperation : AsBiOperation
    {
        public override int Result
        {
            get { return Value1 + Value2; }
        }
    }
    public class MultiplicationOperation : AsBiOperation
    {
        public override int Result
        {
            get { return Value1*Value2; }
        }
    }
Do stworzonej klasy abstrakcyjną i napiszemy test dla wszystkich klas dziedziczących po niej. Dodatkowo mamy możliwość wprowadzenia przykładowych wartości.

    [TestFixture(1,2,3,     TypeArgs = new[] { typeof(SumOperation)} )]
    [TestFixture(0, 0,0,    TypeArgs = new[] { typeof(SumOperation) })]
    [TestFixture(-1, 1, 0,  TypeArgs = new[] { typeof(SumOperation) })]

    [TestFixture(1, 0, 0,   TypeArgs = new[] { typeof(MultiplicationOperation) })]
    [TestFixture(1, 5, 5,   TypeArgs = new[] { typeof(MultiplicationOperation) })]
    [TestFixture(5, 5, 25,  TypeArgs = new[] { typeof(MultiplicationOperation) })]    
    public class AsBiOperationTests<T>
        where T:AsBiOperation, new()
    {
        T operation;
        int _value2;
        int _value1;
        int _result;

        public AsBiOperationTests(int value1, int value2, int result)
        {
            _result = result;
            _value1 = value1;
            _value2 = value2;
        }

        [SetUp]
        public void SetUp()
        {
            operation = new T();
        }


        [Test]
        public void It_should_calculate()
        {
            operation.Value1 = _value1;
            operation.Value2 = _value2;
            Assert.AreEqual(_result,operation.Result);
        }
        
    }

Testy sparametryzowane to fantastyczne rozwiązanie, aby mniej kodować, mieć większe pokrycie kodu i móc więcej przetestować przypadków. Bardzo żałuje, że w MSTest jeszcze nie ma takiego featura (chociaż nie bezpośrednio). Jednak mam nadzieję, że w bliskiej przyszłości coś się z tym zmieni. Oprócz NUnit'a sparametryzowane test są w MBUnit.

piątek, 7 grudnia 2012

Rozpakowanie gz w PowerShell

Ostatnio miałem problem z rozpakowaniem dużej ilości spakowanych plików, wiec musiałem napisać skrypt, który będzie mógł rozpakować wszystkie pliki do wyznaczonego katalogu. Z pomocą przyszedł mi Power Shell, a skrypt wyglądał następująco:
$files = gci -Filter *.zip 
$dirInto = (Get-Location).Path
foreach ($file in $files) {
Write-Host "Processing $file"
$shell_app=new-object -com shell.application
$fileFullName = $file.FullName

$zip_file = $shell_app.NameSpace($fileFullName)
$destinationFolder = $shell_app.NameSpace($dirInto) 
$destinationFolder.CopyHere($zip_file.Items())
}
Rozwiązanie znalazłem na blogu msdn.
Wszystko ok, ale jak chciałem rozpakować pliki gz to już miałem problem. Zabrałem się za przerobienie kodu. Nie chciałem, aby rozwiązanie było uzależnione od jakieś aplikacji, na przykład od PowerShell Community Extensions
Na samym początku napisałem kod w c#, który posłużył mi za podkładke,w którym to korzystam z GZipStream.
using (FileStream fsRead =
 new FileStream(filePath, 
               FileMode.Open, 
               FileAccess.Read,
               FileShare.Read))
            {
                string fileName = 
Path.GetFileNameWithoutExtension(filePath);

                using (FileStream outFile = File.Create(Path.Combine(dirname,fileName)))

                using (GZipStream zipStream= 
new GZipStream(fsRead, 
CompressionMode.Decompress))

                    zipStream.CopyTo(outFile); //.NET 4.0
            }

Później zacząłem przerabiać ten kod na skrypt w PS.
function Unzip-Gzip
{
    param
    (
        [String]$inFile,
        [String]$outDir
    )
 
    if (! (Test-Path $inFile))
    {
        "Input file $inFile does not exist."
        exit 1
    }
 
    if (! (Test-Path $outDir))
    {
        "Output direcotri $outDir does not exist."
        exit 1
    }
   

    $inputFile = New-Object System.IO.FileStream $inFile, 
([IO.FileMode]::Open), 
([IO.FileAccess]::Read), 
([IO.FileShare]::Read)


     try{
        $newFileName = 
[System.IO.Path]::GetFileNameWithoutExtension($inFile)

        $newFilePath = 
[System.IO.Path]::Combine($outDir, $newFileName)  

        $outputDir = 
[System.IO.File]::Create($newFilePath)

        try{
            $inputFileGzip = 
New-Object System.IO.Compression.GZipStream $inputFile, ([System.IO.Compression.CompressionMode]::Decompress)

            try{
                $inputFileGzip.CopyTo($outputDir)
            }finally{
                $inputFileGzip.Close()
            }
        }finally{
            $outputDir.Close()
        }
    }finally{
        $inputFile.Close()
    }
}
Niestety nie mogłem wywołać metody CopyTo, gdyż ta metoda pojawiła się dopiero w .NET 4.0 i nie występuje w PS 2.0. Zamiast tej metody stworzyłem funkcje, która mogła przekopiować Stream.
function Copy-Stream 
{
    param
    (
        [System.IO.Stream]$inputStream,
        [System.IO.Stream]$outputStream
    )

 $bufferSize = 1024
 $buffer = New-Object byte[] $bufferSize
 
 while($true)
 {
    $byteCount = $inputStream.Read($buffer, 0, $bufferSize) 
    if ($byteCount -le 0)
    {
        break;
    }
    $outputStream.Write($buffer,0, $byteCount)
 } 
}

Ostatecznie funkcja Unzip-Gzip wyglada tak:
function Unzip-Gzip
{
    param
    (
        [String]$inFile,
        [String]$outDir
    )
 
    if (! (Test-Path $inFile))
    {
        "Input file $inFile does not exist."
        exit 1
    }
 
    if (! (Test-Path $outDir))
    {
        "Output direcotri $outDir does not exist."
        exit 1
    }
   


    $inputFile = New-Object System.IO.FileStream $inFile,
 ([IO.FileMode]::Open), 
([IO.FileAccess]::Read), 
([IO.FileShare]::Read)

     try{
        $newFileName =
[System.IO.Path]::GetFileNameWithoutExtension($inFile)

        $newFilePath = 
[System.IO.Path]::Combine($outDir, $newFileName) 
 
        $outputDir = 
[System.IO.File]::Create($newFilePath)
        try{
            $inputFileGzip = 
New-Object System.IO.Compression.GZipStream $inputFile, ([System.IO.Compression.CompressionMode]::Decompress)

            try{
#$inputFileGzip.CopyTo($outputDir)
#Not in POWERSHELL 2.0
                Copy-Stream  $inputFileGzip $outputDir
            }finally{
                $inputFileGzip.Close()
            }
        }finally{
            $outputDir.Close()
        }
    }finally{
        $inputFile.Close()
    }
}
A skrypt do rozpakowania plików gz wygląda następująco:
$files = gci -Filter *.zip 
$dirInto = (Get-Location).Path
foreach ($file in $files) {
Write-Host "Processing $file"
$shell_app=new-object -com shell.application
$fileFullName = $file.FullName

Unzip-Gzip $fileFullName  $dirInto
}


Ryan Gosling też programuje

Ryan Gosling - kanadyjski aktor, gitarzysta, a w wolnych chwilach ... programuje


I kto mówił, że język IT nie może być romantyczny :)

Więcej ciekawych zdjęć pod tym blogiem.

Ewolucja lambda expression

Na początku był delegat.


Delegat jest odpowiednikiem wskaźnika do funkcji w C/C++. Jest silnie typowany, co oznacza, że delegat może wskazywać tylko na określony typ metody. Dajmy na to, że potrzebujemy sprawdzić czy pewna wartość jest większa czy mniejsza od zadanego progu. Stwórzmy delegat, który będzie miał 2 argumenty (wartość zmiennej oraz wartość progu) i będzie zwracał bool.
delegate bool ComparisonDelegate
(int value, int threshold);


public static bool IsGreaterThan
(int value, int threshold)
{
    return value > threshold;
}


public static bool IsLessThanOrEqualTo
(int value, int threshold)
{
    return value <= threshold;
}

Zastosowanie takiego delegata wygląda następująco:

ComparisonDelegate greaterThan = 
new ComparisonDelegate(IsGreaterThan);

ComparisonDelegate lessThanOrEqualTo =
new ComparisonDelegate( IsLessThanOrEqualTo);

bool is1GreaterThan3 = 
greaterThan(1, 3);

bool is5LessThanOrEqualTo4 = 
lessThanOrEqualTo(5, 4);

Takie rozwiązanie składała się z wielu linijek kodu oraz z paru oddzielnych części (deklaracja delegata, napisanie oddzielnych metod, inicjacja instancji delegatu, wywołanie delegata).Początki są ciężkie :)
Pierwszym uproszczeniem jest zastosowanie nazwanych metod. Już nie jest potrzebne wywołanie konstruktora z parametrem do metody, tylko wystarczyło podać nazwę metody.
ComparisonDelegate greaterThan = IsGreaterThan;
W .NET 2.0 przyszedł na świat koncept zwany metodami anonimowymi.
delegate bool ComparisonDelegate(int value, int threshold);


ComparisonDelegate greaterThan = delegate
(int value, int threshold)
{
return value > threshold;
};

bool is1GreaterThan3 = greaterThan(1, 3);

Dzięki anonimowym metodom można wprowadzić logikę biznesową do 'ciała'. Już nie musimy deklarować dodatkowych metod. Skoro teraz za każdym razem kiedy tworzymy instancje używamy słowa 'delegate' to można to zamienić na znak '=>'.
ComparisonDelegate greaterThan = 
delegate(int value, int threshold)
{
return value > threshold;
};
ComparisonDelegate greaterThan = 
(int value, int threshold)=>
{
return value > threshold;
};
Od momentu zamiany słowa delegate na znak '=>' mamy do czynienia z lambda expression. Lambda expression są rozwinięciem anonimowych metod. W tym kodzie znak '=>' oznacza, że pobiera 2 argumenty typu int, a zwraca bool. Jeszcze możemy usunąć klamry:
ComparisonDelegate greaterThan = 
(int value, int threshold)=> 
value > threshold;
I skoro wiemy, że ComparisonDelegate przyjmuje dwa argumentami typu int, to możemy tą zduplikowaną informację też usunąć.
ComparisonDelegate greaterThan = 
(value, threshold)=> 
value > threshold;
Po takich operacjach, składnia jest krótsza i czytelniejsza. Całość wygląda następująco:
delegate bool ComparisonDelegate(int value, int threshold);

ComparisonDelegate greaterThan =
(value, threshold)=> 
value > threshold;

bool is1GreaterThan3 = greaterThan(1, 3);
Wraz z .NET 3.5 (c#3.0) możemy użyć generycznego delegata o nazwie Funk. Dzięki temu nie będziemy musieli deklarować dodatkowego elementu. Deklaracja wygląda następująco:
delegate bool ComparisonDelegate(int value, int threshold);

delegate TResult Func<T1, T2, TResult>(T1 arg1, T2 arg2);
Zamieniamy ComparisonDelegate na Func:
Func<int, int, bool> greaterThan = 
(value, threshold)=> 
value > threshold;
Jak widać przejście z delegatów do lambda expressions jest całkiem ... szybkie:)

czwartek, 6 grudnia 2012

Any w listach

Czasami w kodzie widzę coś takiego:
 IEnumerable<int> numbers= new List<int> { 1,2,3,11,22,33};

 if (numbers.Count() > 0)
 { 
   //code... 
 }

Nic wielkiego jeżeli mamy listę do tyś. elementów, ale co się stanie, gdy lista składa się z dużo większej liczby elementów lub elementy są jako 'ciężkie obiekty'. Metoda Count() ma liniową złożoność obliczeniową. Poniższa tabela przedstawia ilość elementów i czas działania metody Count w ms. Oczywiście na innym komputerze czas działania metody będzie inny.

CountCount time
1000
1,0000
10,0000
100,0001
1,000,00013
10,000,000130
100,000,0001332
1,000,000,00013243


Zastanawiam, się dlaczego programiści nie używają metody Any(), która ma złożoność O(1). Metoda ta sprawdza czy jest przynajmniej jeden element w liście. A co jeżeli będziemy chcieli sprawdzić czy w liście jest przynajmniej n-elementów? Ja wpadłem na parę rozwiązań.

if (numbers.Count() >= indexOf)
{
//count
}

if (numbers
.Select((x, i) => new { x, i })
.Any(arg => arg.i >= indexOf))
{
//select&any
}


if (numbers
.Skip(indexOf)
.Any())
{
//skip&any
}

if (numbers
.ElementAtOrDefault(indexOf+ 1) != default(int))
 {
 //elementAt
}

if (numbers
.Take(hasIndexes)
.Count() == indexOf)
{
//take&count
}


Zmienna indexOf określa ile elementów chcielibyśmy, aby było w liście. Metoda ElementAtOrDefault mogła by spełniać warunek zadania tylko wtedy, gdyby lista nie zawierała domyślnej wartości elementu. Poniżej przedstawiam wyniki czasu działania dla tych sposobów. Czas jest liczony w ms.

IndexOfCountSelect&AnySkip&AnyElementAtTake&Count
1282652101
10277690000
100279160000
1,000286040000
10,000284230000
100,000286053112
1,000,0002854132121421
10,000,00028408321128137205
100,000,000285293222130213902065
1,000,000,0002858332342132681378920489

Wykres w skali liniowej i logarytmicznej:



Wniosek jest taki, że najlepiej przeskoczyć potrzebną liczbę elementów w liście i sprawdzić czy jest jakiś element (skip&any).

Gdyby lista byłaby IList<T> to można jeszcze zastosować indexOf lub właściwość Count:

if (numbers
.IndexOf(hasIndexes) != -1)
{

}

Jeżeli znasz inne sposoby to opisz je w komentarzu. Jestem ciekaw co można jeszcze zrobić.

Captured variables

Chciałbym napisać o czymś co się ostatnio dowiedziałem. Kompilator C# używa delegatów nie tylko po to, aby referować do metod, ale również aby przechowywać pewien kontekst - może przechowywać zmienne, aby były dostępne przez różne metody. Przypuśćmy, że mamy taką metodę:
public static bool IsGreaterOrEqualThan(
int value, 
int threshold)
{
 return value >= threshold;
}

Metoda pobiera dwa argumenty. Pierwszy zawiera wartość jaką chcemy sprawdzić, a drugi argument określa wartość progową. Zróbmy z tego predykat - metodę, która zwróci instancje delegata.
public class Pred
{
public static Predicate<int> IsGreaterOrEqualThan(
int threshold)
{
 return value => value >= threshold;
}
}

Wywołanie wygląda następująco:
Predicate greaterorEqualThan100 =
 IsGreaterOrEqualThan(100);

bool isValue1GreaterOrEqual   = greaterorEqualThan100 (1);
bool isValue999GreaterOrEqual = greaterorEqualThan100 (999);

Wartość graniczna (threshold) nie jest argumentem wbudowanej metody (inline method), ale samego predykatu. Kiedy tworzymy instancje predykatu to .NET tworzy dodatkową 'magię'. Kompilator generuje klasę, aby mógł przetrzymywać zmienne. Ta klasa będzie zawierała metodę oraz zmienną. Każde wywołanie metody będzie miało własną wartość zmiennej threshold. Jak pokazuje refleksja, wygenerowana klasa <>c__DisplayClass1 ma nazwę niedozwolona przez c#.
 public class Pred
  {
    public Pred()
    {
      base..ctor();
    }

    public static Predicate<int> 
IsGreaterOrEqualThan(int threshold)
    {
      Pred.<>c__DisplayClass1 cDisplayClass1 = 
new Pred.<>c__DisplayClass1();

      cDisplayClass1.threshold = threshold;

      return new Predicate<int>(
(object) cDisplayClass1, 
__methodptr(<IsGreaterOrEqualThan>b__0));

    }

    [CompilerGenerated]
    private sealed class <>c__DisplayClass1
    {
      public int threshold;

      public <>c__DisplayClass1()
      {
        base..ctor();
      }

      public bool <IsGreaterOrEqualThan>b__0(int value)
      {
        return value >= this.threshold;
      }
    }
  }


Tutaj należy poruszyć dwie ważne kwestie. Uchwycone zmienne (polskie tłumaczenie Captured Variables) mogą spowodować, że kod w pętlach zacznie inaczej działać niż spodziewaliśmy się na samym początku. Po drugie, lokalne zmienne typu ValueType nie zawsze są na stosie (stack) - kompilator kopiuje lokalną zmienną (threshold) do pola obiektu, który znajduje się na stercie (heap). Ta czynność ma bardzo duży wpływ na wydajność aplikacji.

środa, 14 listopada 2012

Świat zwariował na punkcie "Gangnam style"

Gangnam style to nowy hit internetu. Gdy teledysk osiąga sukces to zaczynają pojawiać się przeróbki jak grzyby po deszczu. Chciałbym przedstawić przeróbki, które najbardziej mi się spodobały, a wśród nich są filmiki z udziałem pluralsight, postaci z Mortal Kombat, studentów i więźniów.









Po prostu świat oszalał :)


wtorek, 28 sierpnia 2012

Gry improwizacyjne

Już jakiś czas uczestniczę w krakowskiej grupie improwizacyjnej. Bardzo mi się podoba to co my robimy na spotkaniach i chciałbym ci przedstawić parę moich pomysłów na gry improwizacyjne. Te 11 pomysłów powstało w trakcie robienia innych podobnych ćwiczeń.



1) ADHD

Gra dla 2-3 osób. Tworzy się platformę. Wszyscy aktorzy poruszają się tak samo. Udają, że maja ADHD i wykonują ten sam ruch, na przykład wszyscy skaczą, chodzą na czworakach, tańczą, rozmawiają z podniesioną ręką. Publiczność ustala jaki to jest ruch oraz miejsce akcji. Jest to gra bardzo dynamiczna.



2) Kontekstowy problem.

Gra dla 3 osób. Aktorzy maja do rozwiązania problem. Każda z tych osób musi komunikować się w innym kontekście (są 3 podstawowe konteksty: logiczny, emocjonalny i seksualny). Publiczność określa problem, jakie to są postacie i kto gra w jakim kontekście.



3) Mam dobrą wiadomość

Uczestnicy gry maja przedstawić 2 scenki z taka sama sytuacja i scenariuszem. W pierwszej scence maja do rozwiązania jakiś problem i za każdym razem, kiedy rozwiążą ten problem powstaje nowy, trudniejszy do rozwiązania problem. W drugiej scence uczestnicy maja te same problemy i rozwiązują je w tych samych kolejnościach, ale za każdym razem kiedy pojawia się problem są nastawieni pozytywnie i zaczynają zdanie od "jest super", "jest dobrze", " mam dobre wiadomości" itp. Gra uczy cię, żeby znajdywać coś pozytywnego w problemach.



4) Zagubieni w czasie

Gra jest dla 3 osób. Tworzy się platformę z problemem do rozwiązania. 2 osoby zaczynają scenkę. Publiczność określa jakimi postaciami historycznymi są aktorzy. Każda postać historyczna ma swój sposób na rozwiązanie problemu. Nowa osoba może wejść na scenę w każdej chwili i sama decyduje jaką postacią historyczna jest. Na scenie nie może być więcej niż 2 osoby i mniej niż 1 osoby. Kiedy trzecia osoba wychodzi na scenkę to jedna już uczestniczących osób w tej scence musi zejść. Za każdym razem, gdy osoba wchodzi na scenę jest nowa postacią historyczna.



5) Trzech doradców

Gra dla 3 osób. Publiczność ma pytania do doradców. Doradcy odpowiadają po kolei. Pierwszy doradca chce odpowiedzieć dobrze dla innych i jest perfekcjonistą. Drugi doradca jest sadysta i daje złe rady. Trzeci doradca jest chciwy i odpowiada tak, aby było dobrze dla niego, a złe dla innych ludzi. Po takiej turze jest zamiana postaciami. Każda osoba ma możliwość bycia innym doradca.



6) Problem sąsiada

2 osoby rozgrywają scenkę. Te osoby nie dążą się sympatią. Każda z tych osób ma inny problem do rozwiązania. Oni sami nie mogą rozwiązać tego problemu, ale może to jego sąsiad. Publiczność określa kim są ci sąsiedzi i jakie mają problemy.



7) Amerykański horror

Jest to 6-osobowa gra podobna do opowieści z wakacji. 5 osób bierze udział w grze jako aktorzy i 1 osoba opowiada historie w formie zdjęć. Wśród tych 5 osób jest jeden seryjny morderca. Kim jest seryjny morderca wie tylko on sam i osoba opowiadająca historie. Wszyscy aktorzy umierają. Morderca nie może ukazać się. Inni aktorzy i publiczność muszą zgadnąć kto jest morderca i jak upozorował morderstwo. Inspiracją do tej gry są takie filmy jak Krzyk, Koszmar minionego lata, Ulice strachu, Sekta, Memento, American Psycho czy Oszukać przeznaczenie.



8) Triswitch

3 osoby odgrywają scenkę. Na komendę zmiana, każdy aktor zmienia się postacią. Zmiana jest zgodnie z ruchem wskazówek zegara. Przed grą publiczność określa kim są te postacie i jakie maja relacje. Gra dobrze działa, gdy każdy aktor ma wyznaczony obszar poruszania się.



9) Natarczywy sprzedawca

Gra dla 2 osób. Jeden aktor jest sprzedawca niepotrzebnej, ale wielofunkcyjnej rzeczy, a drugi aktor jest klientem, który nie chce kupić tej rzeczy. Sprzedawca musi wymyśleć zastosowania dla klienta, a klient musi przedstawić kontrargument (wady) produktu, aby nie dokonać zakupu. Największą liczbę ofert jest wysyłana przez sprzedawcę i wymaga od niego większej kreatywności. Wydaje mi się, że w taką grę grają większość sprzedawców.



10) Rozmowa klasyfikacyjna

Gra dla dwóch osób. Osoba szukająca pracy nie wie na jakie stanowisko aplikował. Za pomocą pytań aplikant powinien się domyślić jakie to jest stanowisko. Gra jest z życia wzięta. Kiedyś umówiłem się na spotkanie rekrutacyjne i jedyne co wiedziałem to imię rekrutera oraz miejsce i czas spotkania.

Okazało się, że taka gra już istnieje.



11) Znajomy Alzheimer

To jest gra, która bardzo często występuje w życiu. Do gry potrzebni są 2 aktorów. Jedna jak i druga postać nie wie kim jest jego rozmówca, ale oni sami wiedzą, że znają swojego rozmówcę. Te informacje określa publiczność. Aktorzy próbują nakierunkować się nawzajem używając samych pytań, aby ten drugi aktor mógł zgadnąć kim jest i skąd się znają. Trochę skomplikowana gra, ale wszystko wyjdzie w praniu :)



niedziela, 26 sierpnia 2012

3 role w firmie: Przedsiębiorca, Menedżer i Technik

Chciałbym ci powiedzieć o 3 podstawowych rolach w firmie. Te role to profil techniczny, menedżerski i przedsiębiorczy. Jest to metafora zamieszczona w książce The E-Myth Revisited: Why Most Small Businesses Don't Work and What to Do About It autorstwa Michael E. Gerber. Przedsiębiorca wyznacza kierunek działania firmy, Menedżer zarządza nią, a Technik wykonuje zadania. Według Gerberta, w małej firmie jest 10% przedsiębiorców, 20% menedżerów i 70% osób technicznych. Każda osoba, która zaczyna swoją pracę w firmie ma jedną z tych ról. Problem jest wtedy, gdy każda z tych ról chce być szefem i nikt z nich nie chce mieć szefa. Posiadanie bardzo dobrych techników czy samych menedżerów w firmie nie gwarantuje osiągnięcia sukcesu. Tak samo jest z posiadaniem samych dobrych pomysłów. Dobry pomysł bez odpowiedniego zespołu jest skazany na porażkę.



Kiedy jesteś technikiem to zastanawiasz się nad techniczną implementacją danego zagadnienie. Nie lubisz delegować zadań nowym osobom, bo wiesz, że mogą coś źle zrobić. Zawsze mówisz, "jak chcesz zrobić coś dobrze, to zrób to sam". Jesteś zorientowany na teraźniejszość. Bardzo nie lubisz zmian obecnych planów. Kiedy pracujesz nad swoją pracą to jesteś zadowolony wykonując tą jedną rzeczą. Jeżeli dostaniesz nowe zadania od menedżera to jesteś bardzo zdenerwowany tym, że nie możesz dokończyć wcześniejszego zadania. Najlepsza sytuacja dla ciebie jest, kiedy menedżer dyskutuje z przedsiębiorcą, bo wtedy możesz swobodnie wykonywać swoją pracę. Nie interesujesz się życiem firmy.



Gdy jesteś menedżer to zastanawiasz się jak zoptymalizować procesy, procedury, jak zbudować stabilne środowisko dla firmy oraz jak zarządzać innymi. Jesteś pragmatyczny i żyjesz przeszłością. Dzięki twoim zdobytym doświadczeniom próbujesz dobrze planować (krótko- oraz długodystansowo ) i przewidywać trendy. Masz wszystko poukładane i bardzo nie lubisz dużych zmian. Starasz się być jak najbardziej produktywny. Powtarzasz osobom, że czas to pieniądz. Jesteś osobą, która po przedsiębiorcy "sprząta cały bałagan". Wszelkie zmiany zapisujesz. Musisz mieć dobre zdolności komunikacyjne z technikami, przedsiębiorcami, jak i innymi menedżerami. Stawiasz na gry zespołowe. Jako lider to ty jesteś odpowiedzialny za dobrą atmosferę w zespole. Lubisz delegować zadania innym osobom. Nie znam ludzi, którzy od razu zaczynali pracę od zarządzania osobami. Zanim ktokolwiek zacznie zarządzać innymi technicznymi osobami to wcześniej sam musiał być techniczną osobą, aby zrozumieć wszelkie procesy.



Ty jako przedsiębiorca jesteś marzycielem i masz wizje działania biznesu. Próbujesz znaleźć nowe drogi w firmie. Żyjesz przyszłością. Non stop przychodzą ci do głowy setki pomysłów w ciągu dnia, ale bardzo ciężko jest Ci zrealizować te pomysły. Jako wizjoner preferujesz rozgrywki jednoosobowe. Masz wizje całego systemu i nie koncentrujesz się na szczegółach. Chcesz mieć wszystko pod kontrolą. Za wszelką cenę chcesz kontrolować życie w firmie jak i poza nią. Kiedy będziesz chciał wykonać zadania technika to możesz wszystko popsuć.

Ale w gruncie rzeczy przedsiębiorca sam wcześniej był osobą techniczną. Właściciel firmy wypiekającej ciasteczka wcześniej sam był piekarzem. Właściciel firmy budowlanej zaczyna od pracy u kogoś na budowie. Właścicielka gabinetu stomatologicznego musiała wcześniej pracować jako stomatolog. Wydawca gazety zaczynał jako dziennikarz. Notariusz zaczynał jako aplikant. Większość technicznych osób myśli, żeby osiągnąć sukces w swojej firmie wystarczy mieć tylko techniczną wiedzę. Akurat ta wiedza może lekko przyczynić się do upadku firmy. Według autora tej metafory to przyczyną porażki małych firm jest spowodowane tym, że przedsiębiorcy są osobami technikami, kiedy to powinni spełniać rolę przedsiębiorcy. Wizjoner jest zniewolony zadaniami, których on sam nie powinien wykonywać. Jeżeli firma jest zależna zadaniowo od przedsiębiorcy to ten przedsiębiorca nie jest wizjonerem tej firmy, ale jest pracownikiem. Kiedy technik zaczyna być przedsiębiorcą, to będzie musiał zapomnieć wiele rzeczy jakich wcześniej się nauczył.



Możesz spróbować dopasować siebie do jednego z tych profili. Wiem, że nie jest to łatwe, tym bardziej, że jesteśmy mieszanką każdej z tych ról. Jeżeli twoje stanowisko w firmie jest niezgodny z tym co robisz albo jak postępujesz to możesz to zmienić. Każdego profilu można się nauczyć. To nie jest tak, że ktoś się urodził i od razu wie jak pisać artykuły do gazet, tworzy świetne pomysł czy zna prawo cywilne. Zdobywasz wiedzę i doświadczenie po to, aby być lepszym technikiem. Tak samo jest z profilem managerskim. Nie od razu wiesz jak prowadzić projekt czy jak dobrze rozmawiać z ludźmi. Brak równowagi dla tych ról może spowodować upadek wspólnego projektu. Każda osoba należąca do innej roli może zauważyć inny problem. Technik zauważy problemy techniczne, menedżer złą współpracę między ludźmi, a przedsiębiorca zły kierunek działania firmy.

O książce można poczytać na stronie e-myth.com lub tutaj. Skrót e-myth oznacza entrepreneurial myth.

sobota, 11 sierpnia 2012

Nie bądź krabem

Nie jestem miłośnikiem owoców morza, ale chciałbym Ci opowiedzieć o krabach i krabobraniu. Na ogół kraby są bardzo szybkie. Weźmiesz jednego kraba do pudełka i on ucieknie z niego. Wystarczy, że do tego samego pudełka włożysz drugiego kraba. Kiedy jeden krab będzie chciał wyskoczyć z pudełka, to ten drugi złapie go i nie pozwoli, aby on mógł uciec. Jeden i drugi wie o tym, że zaraz zginie, ale nie pozwoli, aby drugiemu udało się przeżyć. Nawet, gdyby działali osobno to mogli by z tego pudełka uciec. Takie zachowanie można zaobserwować w ludziach i nazywa się to syndromem krabów w wiaderku. Na pewno już spotkałeś się z taką sytuacją. To co mogę Ci doradzić to jak najszybsze odseparowanie się od takiej osoby.




A jeżeli ty jesteś krabem, to wiedz o tym jak one kończą.

wtorek, 26 czerwca 2012

Co jest w Microsoft.VisualBasic

Microsoft.VisualBasic jest niedocenianą biblioteką. Ma bardzo dużo mechanizmów jakich standardowo potrzebuję. W tym poście postaram przedstawić ci te najciekawsze informację o niej.

W Microsoft.VisualBasic znajdują się typy związane z datą. To między innymi FirstDayOfWeek czy DateInterval. Już kilka razy pisałem enum z dniami tygodnia. Inne typy to m.in. TriState

Statyczne klasy Information oraz Interaction mają bardzo przydatne metody.
var isArray1= Information.IsArray(new int[2]); //true
var isArray2 = Information.IsArray(new ArrayList()); //false

var isDBNull = Information.IsDBNull( null); //false

var isReference1 = 
    Information.IsReference(new Int32()); //false

var isReference2 = 
    Information.IsReference(new string('a', 2)); //true

var getRGB = Information.RGB(255, 127, 0); //32767

var isNumeric1 = Information.IsNumeric("123.4"); //true
var isNumeric2 = Information.IsNumeric("123.4 num"); //false

var getTypeName = Information.TypeName(
                 new FieldAccessException());
                 //FieldAccessException

Interaction.Beep();
Interaction.InputBox("Info", "Title");

string decadeRange = 
        Interaction.Partition(80, 0, 99, 10); //" 80: 89"

Zawsze potrzebowałem metody, która sprawdzi mi czy dana zmienna jest DBNull. Interesowało mnie czy jest jakieś okienko z textboxem do wpisania tekstu. Teraz już wiem, że można skorzystać z Interaction.InputBox. Nietypowa metoda jest Interaction.Partition, która zwraca przedział.

Mamy możliwość operacji na stringu, gdzie standardowo w BCL nie było takiej możliwości. Możemy m.in. usuwać wolną przestrzeń tekstu z dowolnej strony.
string text = " te st ";
var r1 = Strings.LTrim(text);
var r2 = Strings.Trim(text);
var r3 = Strings.RTrim(text);

var rightChars = Strings.Right(text,3);
Co ciekawe, w tej biblioteczce znajduje się klasa odpowiedzialna za parsowanie pliku tekstowe. Jest nią TextFiledParser. Za pomocą tej klasy można w prosty sposób parsować plik CSV. Jeżeli będziesz chciał skopiować katalog do innego folderu to będziesz mógł wykorzystać metodę FileSystem.CopyDirectory albo FileSystem.DeleteDirectory, aby usunąć katalog. W tej bibliotece jest jeszcze wiele innych interesujące możliwości, choćby nawet możemy pobrać informacje o komputerze (Devices.ComputerInfo().TotalPhysicalMemory) czy możemy pingować (Network.Ping).
Ta klasa ma jeszcze jedna, bardzo interesująca możliwość. Możemy uruchomić aplikację w postaci singletona.

Testy jednostkowe dla Expression

Pisałem test dla wyrażeń lambda i to co mnie zaskoczyło to test, który nie przechodził dla zmiennych typu epression.
[Test]
public void TestExpressionPlusOne()
{
    Expression<Func<int, int>> increase1 = x => x + 1;
    Expression<Func<int, int>> increase2 = x => x + 1;

    Assert.AreEqual(increase1 , increase2 );
}
Test nie przechodził, gdyż zmienne do porównania są anonimowymi delegatami. Należało skompilować wyrażenie, gdyż CLR próbuję w locie stworzyć nową klasę. Wtedy uzyskałem do porównania dwa skompilowane wyrażenia. Podając argumenty mogłem dostać wartości dla których można porównywać te wyrażenia. Dla łatwiejszej implementacji wykorzystałem atrybut Values, który wypełniał parametr w funkcji.
[Test]
public void TestExpressionPlusOne( 
    [Values(-99,-9,-1,0,1,9,99)] int values)
{
    Expression<Func<int, int>> increase1 = x => x + 1;
    Expression<Func<int, int>> increase2 = x => x + 1;

    Func<Expression<Func<int, int>>, int> 
compileAndInvoke = expression => expression
                                .Compile()
                                .Invoke(values);
 
    Assert.AreEqual(compileAndInvoke (increase1 ), 
                    compileAndInvoke (increase2 ));
 
}
W taki sposób utworzyło się 7 testów dla różnych argumentów wyrażenia.


Testy dla DateTime.Now

Załóżmy, że mamy klasę, w której podajemy dowolną datę i w której jest metoda zwracająca różnicę w ilościach dni między tą datą, a dzisiejszą datą. W implementacji takiego zadania stosujemy statyczną właściwość DateTime.Now. To pole przy każdym wywołaniu ma inną wartość. Problem może pojawić się kiedy będziemy musieli przetestować metodę zwracającą ilość dni (GetDaysFromNow), która w różnych momentach zwraca inny wynik.
    public class NowDateTimeCalculator
    {
        public  DateTime dateTime { get; private set; }
        public NowDateTimeCalculator(DateTime dateTime)
        {
            this.dateTime = dateTime;
        }
 
        public int GetDaysFromNow()
        {
            var timeSpanDiff = DateTime.Now - dateTime;
            return (int)timeSpanDiff.TotalDays;
        }
    }
Mamy kilka sposobów, aby mieć możliwość przetestowania tej klasy. Pierwsza możliwość to zastosowanie pośredniej klasy (interfejsu), która mogłaby dostarczyć informacji o aktualnej dacie. Tworzymy interfejs zwracający datę (Now) oraz klasę implementującą to pole.
    public interface INowDateTime
    {
        DateTime Now { get; }
    }
    public class NowDateTime : INowDateTime
    {
        public DateTime Now
        {
            get { return DateTime.Now; }
        }
   }

Jeszcze będziemy musieli zmienić naszą klasę NowDateTimeCalculator. Parametr z interfejsem będziemy wprowadzać przez konstruktor. To nam uprości pisanie testów.
public class NowDateTimeCalculator
{
    public  DateTime dateTime { get; private set; }
    private INowDateTime nowDateTime;

    public NowDateTimeCalculator(
                               DateTime dateTime,
                               INowDateTime iNowDateTime)
    {
        this.dateTime = dateTime;
        nowDateTime = iNowDateTime;
    }
 
    public int DaysFromNow2()
    {
        DateTime now = nowDateTime.Now;
        var timeSpanDiff = now  - dateTime;
        return (int)timeSpanDiff.TotalDays;
    }
}
Wywołanie wygląda następująco:
var dateTimeToCheck= new DateTime(2012, 06, 26);

var calc = new NowDateTimeCalculator(
dateTimeToCheck, new NowDateTime());

var fromNow= calc.GetDaysFromNow();
W łatwy sposób będziemy mogli zamokować interfejs INowDateTime. Test może wyglądać następująco:
[Test]
public void Check_if_GetDaysFromNow_Work_With_Mock()
{
    DateTime date_26_06_2012 = new DateTime(2012, 06, 26);
    var nowDateTimeMock = new Mock<INowDateTime>();

    nowDateTimeMock
               .Setup(x => x.Now)
               .Returns(date_26_06_2012);

    var calcToday =
 new NowDateTimeCalculator(date_26_06_2012,
                           nowDateTimeMock.Object);
 
   Assert.AreEqual(0, calcToday.GetDaysFromNow());

    var calcTomorrow =
 new NowDateTimeCalculator(date_26_06_2012.AddDays(1),
                           nowDateTimeMock.Object);
 
   Assert.AreEqual(-1, calcTomorrow.GetDaysFromNow());

    var calcYesterday =
 new NowDateTimeCalculator(date_26_06_2012.AddDays(-1),
                           nowDateTimeMock.Object);

    Assert.AreEqual(1, calcYesterday.GetDaysFromNow());
}
Takie rozwiązanie jest łatwe w implementacji i w testowaniu, ale ma 2 ważne wady - tworzymy zależności od interfejsu INowDateTime oraz takie rozwiązanie musi być znane dla całego zespołu.


Innym rozwiązanie jest zastosowanie statycznej klasy.
internal static class SystemTime
{
    internal static Func<DateTime> 
                SetDateTimeNow = () => DateTime.Now;
 
    internal static DateTime Now
    {
        get { return SetDateTimeNow();}
    }
}


public class NowDateTimeCalculator
{
    public  DateTime dateTime { get; private set; }

    public NowDateTimeCalculator(DateTime dateTime)
    {
        this.dateTime = dateTime;
    }
 
    public int GetDaysFromNow()
    {
        DateTime now = SystemTime.Now;
        var timeSpanDiff = now  - dateTime;
        return (int)timeSpanDiff.TotalDays;
    }
}
Testy wyglądają następująco:
[Test]
public void Check_if_GetDaysFromNow_Work_With_SystemTime()
{
    DateTime date_26_06_2012 = new DateTime(2012, 06, 26);

    SystemTime.SetDateTimeNow =
               () => date_26_06_2012;
    var calcToday = 
        new NowDateTimeCalculator(date_26_06_2012);
    Assert.AreEqual(0, calcToday.GetDaysFromNow());


    SystemTime.SetDateTimeNow = 
              () => date_26_06_2012.AddDays(2);
    var calcTomorrow =
    new NowDateTimeCalculator(date_26_06_2012.AddDays(1));

    Assert.AreEqual(1, calcTomorrow.GetDaysFromNow());


    SystemTime.SetDateTimeNow = 
              () => date_26_06_2012.AddDays(-2);
    var calcYesterday =
    new NowDateTimeCalculator(date_26_06_2012.AddDays(-1));

    Assert.AreEqual(-1, calcYesterday.GetDaysFromNow());
}
Takie rozwiązanie pozwala na przyjemniejsze testowanie naszej klasy. Podoba mi się łatwa zmiana aktualnej daty poprzez wyrażenie lambda. 'Wadą' może być to, że korzystamy z globalnej i statycznej klasy, która musi być znana dla całego zespołu.


Jest jeszcze jedno rozwiązanie tego problemu. To rozwiązanie jest znane tylko dla osoby, która pisze testy. Zastosujemy porównywanie wartości uwzględniając przy tym błąd(margines) w wartościach. Do tego potrzebny nam będzie interfejs z informacją o marginesie.
    public interface IMarginComparer<T> 
    {
        T CompareMargin { get; }
    }
Dla naszych testów będziemy musieli zaimplementować dwie porównywające klasy. Porównamy wartości dla typu DateTime oraz int.
public class DateTimeComparer : 
             IComparer<DateTime>, 
             IMarginComparer<TimeSpan>
{
    public DateTimeComparer(TimeSpan marginOfDateTime)
    {
        this.CompareMargin = marginOfDateTime;
    }
 
    public int Compare(DateTime x, DateTime y)
    {
        var margin = x - y;
        if (margin <= CompareMargin)
        {
            return 0;
        }
        return new Comparer(CultureInfo.CurrentUICulture)
                                       .Compare(x, y);
    }
 
    public TimeSpan CompareMargin
    {
        get; private set; 
    }
}
 



public class IntComparer : 
             IComparer<int>, 
             IMarginComparer<int>
{
    public IntComparer(int margin)
    {
        CompareMargin = margin;
 
    }
    public int Compare(int x, int y)
    {
        var diff = x - y;
        if (diff <= CompareMargin)
        {
            return 0;
        }
        return new Comparer(CultureInfo.CurrentUICulture)
                                       .Compare(x, y);
    }
    public int CompareMargin { get; private set; }
} 
Mając margines możemy określić jaka może być różnica między aktualną, a oczekiwaną wartością. Aby obliczyć ten margines będziemy musieli znać datę pisania testu (dateTimeCodeWritten) i na podstawie tej daty obliczamy ilość dni na różnicę. Gdybyśmy tą różnicę nie obliczyli, a wpisalibyśmy stałą wartość to mogłoby się okazać, że któregoś dnia wszystkie nasze testy przestałyby przechodzić.
[Test]
public void Check_if_GetDaysFromNow_Work_With_Comparer()
{
var dateTimeCodeWritten = new DateTime(2012, 06, 25);
DateTime date_20_06_2012 = new DateTime(2012, 06, 20);

var calc = new NowDateTimeCalculator(date_20_06_2012);

var dateTimeCodeWrittenDiffTimeSpan =
 DateTime.Now - dateTimeCodeWritten;

int dateTimeDiffDays = 
(int)dateTimeCodeWrittenDiffTimeSpan.TotalDays;



var dateTimeComparer = 
new DateTimeComparer(new TimeSpan(dateTimeDiffDays, 0, 0,0));

Assert.IsTrue(dateTimeComparer
.Compare(calc.dateTime.AddDays(5), DateTime.Now) == 0);


var intComp = new IntComparer(dateTimeDiffDays);

Assert.IsTrue(intComp
.Compare(calc.GetDaysFromNow(), 5) == 0);  
   
}
Nie jest to najlepiej napisany test, ale można przetestować DateTime.Now. Zaletą tej techniki jest to, że nie musimy znać (zmieniać) implementacji kodu.

Te rodzaje rozwiązań można zastosować dla wielu innych statycznych metod w tym danych środowiskowych takich jak Environment.MachineName czy Thread.Sleep().

poniedziałek, 25 czerwca 2012

Double są szalone

Typ podwójnej precyzji zawarty w .NET jest bardzo dziwny. Zapisując liczbę mamy tak naprawdę liczbą zaburzoną pewnym błędem reprezentacji.
Poniższe przykłady przedstawiają "dokładność" metody zaokrąglającej oraz prostą operację dodawania.
double res0 = Math.Round(0.500000000000000000000000000D); //0
double res1 = Math.Round(1.500000000000000000000000000D); //2
double res2 = Math.Round(2.500000000000000000000000000D); //2
double res3 = Math.Round(3.500000000000000000000000000D); //4
double res4 = Math.Round(4.500000000000000000000000000D); //4
double res5 = Math.Round(5.500000000000000000000000000D); //6
double res6 = Math.Round(6.500000000000000000000000000D); //6
W komentarzach jest informacja co metoda zwraca.
double d = 0D;
decimal m = 0M;
 
double growD = 0.1D;
decimal growM = 0.1M;
for (int i = 0; i < 10; i++)
{
    d += growD;
    m += growM;
    Console.WriteLine("double :" + d.ToString("R"));
    Console.WriteLine("decimal:" + m.ToString("G"));
    Console.WriteLine();
}
 
A wynik prostego dodawania przedstawiony jest poniżej:



Jak widać na doublach można się mocno przejechać.

wtorek, 19 czerwca 2012

Komendy Finder

Korzystam z maca i niestety muszę korzystać z Findera. Na moje nieszczęście jestem na niego skazany. Oczywiście mogę zainstalować takie aplikacje jak Path Finder, Xfile, BBEdit, Smultron czy Disk Order. Wszystkie te pozycje są płatne ( kosztują odpowiednio 40$, 59$, 49.99$, 4.99$, 29.95$ - już wiem dlaczego programiści od maca lepiej zarabiają). W końcu znalazłem zastępnik Findera tak, aby był bezpłatny. Jest nim muCommander (odpowiednik TotalCommander pod maciem). Ale skoro już wylałem tyle łez, nie przespałem wiele nocek i wydłubałem sobie klawisze, to pozwoliłem sobie na napisanie krótkich wskazówek na temat Findera.



Wszystkie komendy zawarte w tych wskazówkach należy wywołać w terminalu. Po wywołaniu danej komendy należy uruchomić ponownie Findera (przytrzymaj klawisz opcji i prawym przyciskiem kliknij na ikonkę Findera, która znajduje się w docku).

1) Finder nie pokazuje ukrytych folderów i plików
Jeżeli jesteś użytkownikiem Findera i miałeś coś wspólnego z Unixem to z pewnością wiesz, że Finder nie wyświetla plików ukrytych (nazwa plików zaczyna się od . tak jak .bashrc) oraz niektórych folderów (m.in /usr, /bin, /etc i takie tam)
defaults write com.apple.finder AppleShowAllFiles TRUE
Możesz również pobrać AppleSkrypt, który wykonuje tą komendę za ciebie.

2) Ścieżka katalogu w tytule

defaults write com.apple.finder _FXShowPosixPathInTitle -bool YES


3) Zamykanie Findera
Findera nie da się zamknąć, gdyż on pracuje cały czas w tle. Aby móc zamknąć Findera wywołaj tą komendę:
defaults write com.apple.Finder QuitMenuItem -bool YES
Po każdym wykonaniu tych komend pamiętaj, aby uruchomić ponownie Findera. Mam nadzieję, że ten post był dla ciebie przydatny.

P.S. Tej post miał nazywać się F**k Finder

Czy goto ma zastosowanie w c#

Goto to zło. Ale w niektórych sytuacjach przydaje się.



Aby zobrazować dobre wykorzystanie goto przedstawię ci kod. 2 razy iterujemy po macierzy. Jeżeli znajdziemy element, który ma wartość 0 to kończymy tą podwójną pętle. Do tego będziemy potrzebować przerwania pierwszej pętli oraz zmienną informującą o tym czy zostało dokonane przerwanie. Przydałaby się instrukcja doublebreak, która mogłaby zakończyć dwie pętle :/

            int[,] ints = new int[2, 2];
            for (int i = 0; i < 2; i++)
            {
                bool breakSet = false;
                for (int j = 0; j < 2; j++)
                {
                    if (ints[0, 0] == 0) //check if is zero
                    {
                        breakSet = true;
                        break;
                    }
                }
                if (breakSet)
                {
                    break;
                }
            }


Ok, kod jest prosty. Dajmy na to, że zamiast 2 pętli for mamy 4 pętle for.
int oneDimSize = 2;
int[, , ,] ints = new int[oneDimSize, 
oneDimSize,
oneDimSize,
oneDimSize];

bool breakSetForI = false;
for (int i = 0; i < oneDimSize; i++)
{
    bool breakSetForJ = false;
    for (int j = 0; j < oneDimSize; j++)
    {
        bool breakSetForK = false;
        for (int k = 0; k < oneDimSize; k++)
        {
            bool breakSetForL = false;
            for (int l = 0; l < oneDimSize; l++)
            {
                if (ints[i, j, k, l] == 0)
                {
                    breakSetForL = true;
                    break;
                }
            }
            if (breakSetForL)
            {
                breakSetForK = true;
                break;
            }
        }
        if (breakSetForK)
        {
            breakSetForJ = true;
            break;
        }

    }
    if (breakSetForJ)
    {
        breakSetForI = true;
        break;
    }
}

Tutaj już duplikujemy instrukcje if i musimy skorzystać z 4 zmiennych. To samo za pomocą goto wygląda następująco:
int oneDimSize = 2;
int[, , ,] ints = new int[oneDimSize,
 oneDimSize,
 oneDimSize,
 oneDimSize];

bool breakSet = false;
for (int i = 0; i < oneDimSize; i++)
{
    for (int j = 0; j < oneDimSize; j++)
    {
        for (int k = 0; k < oneDimSize; k++)
        {
            for (int l = 0; l < oneDimSize; l++)
            {
                if (ints[i, j, k, l] == 0)
                {
                    goto LabelIsZero;
                }
            }
        }
    }
}
return;

LabelIsZero:
breakSet = true;

Kod z zastosowaniem goto jest zdecydowanie czytelniejszy. Gdybyś miał jakiś inny pomysł na dobre zastosowanie goto to daj znać.



poniedziałek, 28 maja 2012

Zrozumieć LinkedList

Klasa LinkedList jest w .NET Base Class Library od bardzo dawna (od wersji 2.0) i bardzo rzadko jest używana. Zawsze była dla mnie pewną tajemnicą, więc postanowiłem zrobić parę testów na tej klasie. Ogólny sposób działania linked listy można poczytać na stronie wikipedii. Poniżej przedstawiam w punktach krótką charakterystykę:

1) LinkedList występuje tylko w postaci generycznej (LinkedList<T>).

2) LinkedList nie jest "listą" - to znaczy, że nie implementuje interfejsu IList. Interfejsy z których implementuje LinkedList to:
  • ICollection<T>, ICollection
  • IEnumerable<T>, IEnumerable
  • ISerializable, IDeserializationCallback

Dla uproszczenia słownictwa przyjmujemy, że LinkedList<T> i List<T> będziemy nazywać listą.

3) Metody AddFirst i AddLast określają kolejność zapisywanych obiektów. Możemy w prosty sposób dodać obiekt na końcu listy jak i na początku
NP:
var linkedList = new LinkedList<int>();  
//tworzy LinkedList

            linkedList.AddFirst(1);    
//   1 

            linkedList.AddFirst(2);    
//   2, 1

            linkedList.AddFirst(3);    
//   3, 2, 1


            linkedList.AddLast(4);     
//   3, 2, 1, 4 

            linkedList.AddLast(5);     
//   3, 2, 1, 4, 5

            linkedList.AddLast(6);     
//   3, 2, 1, 4, 5, 6




4) Możemy dodać element do wyznaczonego węzła
var linkedList = new LinkedList<int>();            
//tworzy LinkedList

            var objOne= linkedList.AddFirst(1);                
// 1

            var objTwo =   linkedList.AddAfter(objOne, 2);     
// 1, 2

            var objThree = linkedList.AddBefore(objTwo, 3);    
// 1, 3, 2

            var objFour =  linkedList.AddAfter(objThree, 4);   
// 1, 3, 4, 2

            var objFive =  linkedList.AddAfter(objFour, 5);    
// 1, 3, 4, 5, 2



5) LinkedList nie stosuje się we wszystkich zagadnieniach. Poniżej przedstawiam wyniki czasu działa różnych operacji na LinkedList i List. Wyniki są przedstawiane w milisekundach dla tysiąca, 10 tysięcy, 100 tysięcy oraz miliona elementów w listach. Na początku implementacja:
            var list = new List<int>();
            var linkedList = new LinkedList<int>();
            Stopwatch watchLinkedList = new Stopwatch();
            Stopwatch watchList = new Stopwatch();

5a) Dodawanie elementu na końcu listy.
            watchList.Start();
            for (int i = 0; i < counts; i++)
            {
                list.Add(i);
            }
            watchList.Stop();

            watchLinkedList.Start();
            for (int i = 0; i < counts; i++)
            {
                linkedList.AddLast(i);
            }
            watchLinkedList.Stop();


Wykres jest przedstawiony w skali liniowej. Poniżej tabela z wynikami:

Add Last
 LinkedListList
1,00000
10,00000
100,00091
1,000,00010613
10,000,0002770256

Bardzo dokładnie widać, że czas dodawania elementu na koniec listy dla LinkedList jest większy niż dla List.

5b) Dodawanie elementu na początku listy
            watchList.Start();
            for (int i = 0; i < counts; i++)
            {
                list.Insert(0,i);
            }
            watchList.Stop();

            watchLinkedList.Start();
            for (int i = 0; i < counts; i++)
            {
                linkedList.AddFirst(i);
            }
            watchLinkedList.Stop();


Add First
 LinkedListList
1,00000
10,000025
100,00082347
1,000,00097274540

Wykres jest przedstawiony w skali logarytmicznej. Tutaj dokładnie widać, że czas dla List jest dużo większy od LinkedList. Dla 100 tys. jest około 300 razy większy, a dla miliona elementów jest z 3 000 razy większy.

Sprawdźmy co się stanie, gdy porównamy dla LinkedList metodę AddFirst (dodawanie elementu na początek listy) z metodą AddLast (dodawanie elementu na koniec listy). Okazuje się, że czasy dla tych operacji są bardzo zbliżone.


Add FirstAdd Last
1,00000
10,00000
100,00089
1,000,00097106
10,000,00027752770


5c) Usuwanie podanego elementu z gotowej listy (za pomocą metody Remove(int))

Remove
 LinkedListList
1,00000
10,000024
100,00022370
1,000,00030283608

Czas dla List<T> przy operacji usunięcia elementów jest bardzo duży. Wiąże się to z koniecznością "przebudowania" listy (klasa List<T> jest zaimplementowania za pomocą Array).

5d) Sortujemy elementy. Do tego zastosujemy metodę rozszerzającą OrderBy

OrderBy
 LinkedListList
1,00004
10,00011
100,0001819
1,000,000212233
10,000,00033353092

Czas poświęcony na sortowanie listy dla obu klas jest bardzo podobny.

5e) Dodawanie elementu w sam środek listy
Kod dla List:
for (int i = 0 ; i < counts ; i++)
{
  int center = (int)
        Math.Floor( (double)list.Count / 2 );
  list.Insert( center, i );
}

Kod dla LinkedList:
bool addBefore = false;
LinkedListNode<int> centerNode = linkedList.AddFirst(0); ;
for (int i = 1; i < counts; i++)
{
if (addBefore)
{
  centerNode = linkedList.AddBefore( centerNode, i );
  addBefore = false;
}
else
{
  centerNode = linkedList.AddAfter( centerNode, i );
  addBefore = true;
}
}


Add Inner
 LinkedListList
1,00010
10,000015
100,00091467
1,000,000155148823
10,000,000273619992188

Wykres jest przedstawiony w skali logarytmicznej. Operacja na 10 milionach elementach w LinkedList jest podobnie czasochłonna co operacja na 100 tysiącach dla List. W tym eksperymencie ewidentnie widać, że lepiej jest zastosować LinkedList.

Poniżej jest porównanie 3 operacji. Dodawanie elementu na początek listy, w środek i na koniec list. Wyniki są prawie identyczne.
Add FirstAdd InnerAdd Last
1,000010
10,000000
100,000899
1,000,00097155106
10,000,000277527362770


5f) Przechodzenie po liście. Dla uproszenie sprawdzę wykonania operacji foreach oraz znajdę liczbę maksymalną.

ForeachMax
 LinkedListListLinkedLIstList
1,0000000
10,0000000
100,0001011
1,000,000951511
10,000,0009666165118

Wnioski: LinkedList<T> bardzo dobrze sprawuje się przy modyfikacji (dodawanie i usuwanie) obiektów w liście, natomiast List<T> dobrze sprawdza się przy dodawaniu elementu na końcu listy. Z racja, że LinkedList<T> nie ma indeksu to przechodzenie po liście jest kosztowniejsze niż dla List<T>.


środa, 23 maja 2012

Starter.bat

Każdego dni rozpoczynam pracę od uruchamiania tych samych programów, przeglądania tych samych stron, czytania tej samej poczty. Aby zautomatyzować proces klikania po wszystkich ikonkach i wpisywania tych samych nazw, stworzyłem mały .bat plik



Poniżej przedstawiam skrypt w pliku Starter.bat:
:: uruchamia pocztę outlook i zaznacza kalendarz
start outlook.exe /select outlook:calendar

:: wchodzi na strony za pomocą domyślnej przeglądarki
start http://arekonsoftware.blogspot.com  
start https://mail.google.com/mail/#inbox 

:: startuje aplikacje (devenv to visual studio)
start devenv  "C:\Users\I\Documents\Visual Studio 11\Projects\MyBigSolution.sln" /projectconfig Debug 

:: otwiera plik
start /D "C:\Users\I\Documents\" ToDo.xls  

Skrypt zawiera przykładowe programy do uruchomienia. Największą zaletą takiego skryptu jest prostota. Za pomocą polecenia start uruchamiamy daną aplikację. Wiem, że ta technika nie jest czymś odkrywczym, ale dla mnie taki mały pliczek pozwala mi na zautomatyzowanie powtarzalnych czynności. Ta technika jest przydatna, jeżeli masz więcej niż 5 aplikacji do uruchomienia.


Aggregate - One Method to rule them all

LINQ w C# wywarł ma mnie ogromny wpływ. Za pomocą tej technologii mogłem operować na obiektach tak jak za pomocą SQLa. Na przykład przy użyciu metod Where i Sum mogłem prosto i szybko sumować liczby, które są parzyste. Problem pojawia się kiedy chciałbym wykonać coś bardziej skomplikowanego lub złożonego, na przykład obliczyć odchylenie standardowe. Pierwsze rozwiązanie jakie przychodzi mi do głowy to stworzenie metody do obliczenia. Takie rozwiązanie jest dobre, więc kiedyś stworzyłem projekt z samymi extension metods. Projekt można pobrać z codeplex.com. Ale czy za każdym razem należy tworzyć nową metodę? Czy nie możemy zastosować już dostępnych metod do manipulacji kolekcją danych? Z pomocą przychodzi nam niedoceniana metoda Aggregate. Ta funkcja jest do agregacji elementów. Poniżej przedstawiam jej zastosowanie.



Na początku zastąpię proste metody jak suma, count, all i concat za pomocą aggregate.

var ints = Enumerable.Range(0, 10);
var sum1 = ints.Sum();
var sum2 = ints.Aggregate( ( agg, item ) => agg + item );


var count1 = ints.Count();
var count2 = ints.Aggregate(0,(agg, item) => agg + 1, x=>x);

var median1 = ints.ElementAt(ints.Count()/2);
var median2 = ints.Aggregate( 0, ( info, item ) => info = info + 1,
                             x => ints.ElementAt( x / 2 ) );

var all1 = ints.All(x => x > -1);
var all2 = ints.Aggregate( true,
               ( info, item ) =>
               {
               if (info == true && item > -1)
               {
                  return true;
               }
                  return false;
               },
               x => x);


var secondInts = Enumerable.Range(12, 3);
var concat1 = ints.Concat( secondInts );
var concat2 = secondInts.Aggregate( new List<int>( ints ),
              ( list, i )=> { list.Add( i ); return list; },
               list => list );
                     
Ok, to teraz bardziej statystyczne funkcje.
var range1 = ints.Max() - ints.Min();
var range2 = ints.Aggregate( new
{ Max = ints.First(), Min = ints.First() },
( x_range, item ) =>{
     var max = x_range.Max;
     var min = x_range.Min;
     if (max < item)
         max = item;
     
     if (min > item)
         min = item;
     
     return new {Max = max, Min = min}; },
     x_range => x_range.Max - x_range.Min);



var intsRepeatable = ints.Concat( new List<int> { 1, 2, 2, 5, 6 } );
var mode1 = intsRepeatable
            .ToLookup( x => x )
            .OrderByDescending( x => x.Count() )
            .Select( x => x.Key ).First();

var mode2 = intsRepeatable.Aggregate( new Dictionary<int, int>(),
                          ( dic, item ) =>
                          { if (dic.Keys.Contains( item ))
                                dic[item]++; 
                           else
                                dic.Add( item, 1 ); 
                           return dic;
                          },
                          dic => 
                              dic.OrderByDescending( x => x.Value )
                                 .First())
                          .Key;

        

A na koniec ciekawsze smaczki, czyli średnia krocząca dla 3 okresów i odchylenie standardowe.
int movingMeanCounter = 3;
var movingMean3 = ints.Aggregate(
                    new
                    {
                    List = new List<List<int>>(),
                    Counter = 0
                    },
                    ( info, item ) =>
                    {
                        info.List.Add( new List<int>() );
                        for (int i = 0 ; 
                        i < movingMeanCounter 
                            && info.Counter - i >= 0 ; 
                        i++)
                        {
                        var vList = info.List[info.Counter - i];
                        vList.Add( item );
                        }

                        return new
                        {
                        List = info.List,
                        Counter = info.Counter + 1
                        };
                    },
                    x => x.List.Select( item => item.Average() ));

var stdDev = ints.Aggregate( new
                    {
                    Mean = 0,
                    Sum = 0,
                    i = 0
                    },
                    ( info, item ) =>
                    {
                        var i = info.i + 1;
                        var delta = item - info.Mean;
                        var mean = delta / i;
                        var sum = info.Sum + delta * (item - mean);
                        return new
                        {
                            Mean = mean,
                            Sum = sum,
                            i = i
                        };
                    },
                    x => x.i < 2 
                        ? 0 
                        : Math.Sqrt( x.Sum / (x.i - 1) ));            

Możemy wiele ciekawych rzeczy zrobić za pomocą aggregate. Gdybyś miał pomysł na zastosowanie tej metody to jestem otwarty na propozycje. Więcej o niej można poczytać tutaj.