Sortowanie rozmiaru plików

0

Mam wartości w ListView:

34,21 kB
527,20 kB
12,01 MB
0 bajtów
6,42 MB
267 bajtów

jak można posortować te wartości uwzględniając wielkość pliku od 0 bajtów wzwyż ?, tj

0 bajtów
267 bajtów
34,21 kB
527,20 kB
6,42 MB
12,01 MB

Myślałem, aby sortować tylko według bajtów, ale mam nadzieję, że zaproponujecie mi inne rozwiązanie ;-)

0

Można najpierw sprawdzać jaka to jednostka (sprawdzenie od spacji do końca) i wtedy przeliczać na odpowiednią wartość (np. wszystko sprowadzać do bajtów, kilobajtów).

0

ja tam jestem za przeliczeniem na jedną jednostkę, np. bajty i wtedy to prościzna, ew. można próbować tak jak jest teraz ale co np. z 120B i 0.1kB? - i tak trzeba przeliczyć...

0

Rozmiary naliczane są w ten sposób że bajty są od 0b do 1024b, potem już są kilobajty, czyli 1KB do 1024KB, następnie megabajty, itd. A więc nie ma czegoś takiego jak 0,12KB lub 0,86MB.

A przechowywać wartości w bajtach, aby ułatwić sobie sortowanie to operowanie na Integer64, a to już sporo jak na zmienną.

0

no to sortowanie <ort>dwóprzebiegowe </ort>- najpierw po jednostce a potem po rozmiarze

0

Szukając rozwiązania, nie znalazłem nic ciekawego. Nie mam też czasu, więc proponuje:

Zapłacę 25zł za napisanie kodu, który:
Posortuje rozmiar plików (bajty, KB, MB), (uwaga: nie może to być sortowanie na podstawie bajtów, tylko np.: sposób Miska)
i posortuje ilość plików (1 plik, 2 pliki, 10 plików, 20 plików, 101 plików, itd).

Propozycje proszę na [email protected]

0

Juz sie zabieram do pisania... Przesle Ci wynik, a potem tu wstawie (po przelewie :P )

0

co to za jednostka KB?

0
ŁF napisał(a)

co to za jednostka KB?

Kielono bajt xD

(powinno byc kB)

0

Oczywiście kB (kilobajt).
Forma KB i kB jest poprawna z punktu informatyka.

Niepoprawna byłaby Kb a tym bardziej kb, gdzie b - bit.

Wiki: http://pl.wikipedia.org/wiki/Kilo

W informatyce oznacza on 210 (1024) i bywa wówczas również oznaczany wielką literą K, np. 1KB to jeden kilobajt.

0

wikipedia czasem zawiera błędy, akurat w tym miejscu też. nie istnieje taki przedrostek, jak "K".
poniżej leży 25 zeta.

uses classes;
type
  ta = array[1..10] of string;
var
  a : ta = ('100kB','1kB','2MB','1','3B','13kB','1GB','3B','0.1kB','7TB');


function stringToSize(const s : string) : int64;
var
  i, j : integer;
  k    : int64;
  m    : string[16];
  r    : single;
begin
  k := 1;
  j := length(s);
  m := '';
  for i := 1 to j do
  if s[i] in ['0'..'9','.',','] then m := m + s[i] else begin j := i; break end;
  {$R-}
  val(m, r, i); if i > 0 then raise EParserError.Create('Błąd przy konwersji (przecinek zamiast kropki?)');

  if j < length(s) then
  begin
    m := '';
    for i := j to length(s) do
    if upcase(s[i]) in ['A'..'Z'] then m := m + upcase(s[i]); // upcase, bo co poniektórzy nie odróżniają kilobitów od kilobajtów... kb, kB, KB, może jeszcze Kb?!?

    if m = 'B'  then else
    if m = 'KB' then k := 1 shl 10 else
    if m = 'MB' then k := 1 shl 20 else
    if m = 'GB' then k := 1 shl 30 else
    if m = 'TB' then k := int64(1) shl 40 else
    if m = 'PB' then k := int64(1) shl 50;
  end;

  result := round(k*r);
end;


function compare(a,b : string) : integer;
var
  m,n : int64;
begin
  m := stringToSize(a);
  n := stringToSize(b);

  if (m < n) then result := 1 else
  if (m > n) then result := -1 else
  result := 0;
end;

procedure QuickSort(iLow, iHigh : Integer;var A : array of string);
var
  iLo, iHi : Integer;
  x, Temp : string;
begin
  iLo := iLow;
  iHi := iHigh;

  X := A[(iLow + iHigh) div 2];
  repeat
      while compare(A[iLo], X) > 0 do Inc(iLo);
      while compare(A[iHi], X) < 0 do Dec(iHi);
      if (iLo <= iHi) then
      begin
        Temp := A[iLo];A[iLo] := A[iHi];A[iHi] := Temp;
        Inc(iLo);
        Dec(iHi);
      end;
  until iLo > iHi;
  if (iHi > iLow) then QuickSort(iLow, iHi, A);
  if (iLo < iHigh) then QuickSort(iLo, iHigh, A);
end;


var
  table : array of string;
  i : integer;
begin
  setlength(table,high(a));
  for i := 1 to high(a) do table[i-1] := a[i];


  QuickSort(0,high(a)-1, table);
end.

BTW rok czasu szukałeś rozwiązania (13-04-2007 08:50, 23-05-2008 14:43)? ;-)

0

OK, sprawdzę to i na pewno dam znać. Skontaktuję się tak jak ustaliłem, aby zapłacić (email masz więc nie będzie problemu).

Dzięki

0
ŁF napisał(a)

poniżej leży 25 zeta. (...)

Ładnie to sie tak za przeproszeniem ort!? Przeciez napisalem, ze sie za to zabralem. Mam to juz gotowe i co? Co to jest? Jakis wyscig szczurow? Kto pierwszy?

0

ŁF Sprawdziłem i wysłałem ci emaila.

WIktorDelphi: No to teraz masz konkurenta. Wiktor podesłałem ci przykład na mejla - daj znać.

rok czasu szukałeś rozwiązania (13-04-2007 08:50, 23-05-2008 14:43)?

Na to wygląda :/

// ŁF a nie ŁK - Ł

0
WIktorDelphi napisał(a)

Ładnie to sie tak za przeproszeniem ***? Przeciez napisalem, ze sie za to zabralem. Mam to juz gotowe i co? Co to jest? Jakis wyscig szczurow? Kto pierwszy?

synuś, wyrażaj się; jak zacząłem pisać, to nie było twojego posta, poza tym g**no mnie obchodzi, kto był pierwszy, zarówno z "zaklepywaniem", z rozwiązaniem, jak i z kasą. jak jesteś taki zdesperowany, to dokończ Opiemu projekt i sobie weź te drobniaki.

@Opi - nie mam siły wsadzać sortowania do Twojego kodu, daj to wiktorowi, niech się wyżyje.

0
ŁF napisał(a)

jak jesteś taki zdesperowany, to dokończ Opiemu projekt i sobie weź te drobniaki.

@Opi - nie mam siły wsadzać sortowania do Twojego kodu, daj to wiktorowi, niech się wyżyje.

No no, widzę, że ciekawie się porobiło :/

Rozumiem, że 25zł to bardzo mało dla Ciebie jak za kilku dziesięciominutowe napisanie kodu.
Zdaje się, że teraz to wyżej się cenią na tym forum, niż jakimiś tam "drobniakami".

Najwidoczniej miałeś gotowy kod, a teraz nie umiesz tego wykorzystać w przykładzie.

Dobrze, że nie tylko jedna osoba się odezwała w tym temacie.

Projekt jest nadal aktualny, więc oczekuję sensowej odpowiedzi z wykorzystaniem w przykładzie.

0

haha, rozszyfrowałeś mnie. ale na szczęście do Twojego problemu z sortowaniem rozmiaru po kliknięciu na kolumnę listview też znalazłem gotowca ;]
projekt zamknięty.

[dopisane]
co do kasy - za drugą, nudną część "projektu" poproszę te drobniaki. będę mieć na wino, żeby się odstresować po wiktorze.
kod wysłałem, zanim napisałem tego posta. nie ma sensu tego publikować, przecież to proste klikanie na kolumnach.

0
ŁF napisał(a)

haha, rozszyfrowałeś mnie. ale na szczęście do Twojego problemu z sortowaniem rozmiaru po kliknięciu na kolumnę listview też znalazłem gotowca ;]
projekt zamknięty.

To podziel się, skoro nie chcesz zarobić, pomóż za darmo dla ogółu.

0

To ja wstawie swojego niegotowca, tak dla przykladu, ze mozna to zrobic inaczej:

procedure TForm1.Button1Click(Sender: TObject);
const
  iloscJednostek = 4;
  NazwyJednostek: array [0..iloscJednostek] of string = (('bajtów'), ('kb'), ('mb'), ('gb'), ('tb'));
var
  posortowane: array [0..iloscJednostek] of array of single;
  s, wartosc: string;
  obliczonaWartosc: double;
  licznik, l2, l3: integer;
  nrJednostki: byte;
begin
  //przebieg pierwszy -> sortowanie jednostek
  nrjednostki := 0;
  while (nrJednostki <= iloscJednostek) do
  //for nrJednostki := 0 to iloscJednostek do
  begin
    s := '';
    for licznik := 0 to (ListBox1.Items.Count - 1) do
    begin
      s := Trim(Copy(ListBox1.Items.Strings[licznik], Pos(#32, ListBox1.Items.Strings[licznik]), 7));
      if (LowerCase(s) = NazwyJednostek[nrJednostki]) then
      begin
        wartosc := Trim(Copy(ListBox1.Items.Strings[licznik], 1, Pos(#32, ListBox1.Items.Strings[licznik])));
        SetLength(posortowane[nrJednostki], Length(posortowane[nrJednostki]) + 1);
        posortowane[nrJednostki, High(posortowane[nrJednostki])] := -1;
        //"przebieg" drugi -> sortowanie wartosci odpowiednich jednostek
        obliczonaWartosc := StrToFloat(wartosc);
        if (High(posortowane[nrJednostki]) > 0) then
        begin
          for l2 := 0 to High(posortowane[nrJednostki]) do
          begin
            if (posortowane[nrJednostki, l2] >= obliczonaWartosc) or (posortowane[nrjednostki, l2] = -1) then
            begin
              //przesunięcie tablicy
              if (l2 < High(posortowane[nrJednostki])) then
              for l3 := High(posortowane[nrJednostki]) downto (l2 + 1) do
              posortowane[nrJednostki, l3] := posortowane[nrJednostki, l3 - 1];
              //wstawienie wartosci
              posortowane[nrJednostki, l2] := obliczonaWartosc;
              break;
            end;
          end;
        end
        else
        posortowane[nrJednostki, High(posortowane[nrJednostki])] := obliczonaWartosc;
      end;
    end;
    inc(nrJednostki);
  end;
  //wpisanie posortowanych wartosci do ListBoxa
  ListBox1.Clear;
  for nrJednostki := 0 to iloscJednostek do
  begin
    if (High(posortowane[nrJednostki]) > 0) then
    for licznik := 0 to High(posortowane[nrJednostki]) do
    ListBox1.Items.Add(FloatToStr(posortowane[nrJednostki, licznik]) + #32 + NazwyJednostek[nrJednostki]);
  end;
end;

Przystosowanie go do ListView nie jest problemem.

A Panu:

ŁF napisał(a)

będę mieć na wino, żeby się odstresować po wiktorze

pozostaje życzyc smacznej siarki ;)

0

A jak z sortowaniem ?

ilość plików (1 plik, 2 pliki, 10 plików, 20 plików, 101 plików, itd).

tak, aby uzyskać:

1
2
10
20
101

a nie:

1
10
101
2
20

Liczę, że "za darmo" też zrobicie

0

@Wiktor: skoro tak sobie wtykamy szpileczki - niezła złożoność obliczeniowa, cztery zagnieżdżone pętle. do tego... nie działa. wrzuciłem mu 3B, 1kB, 7TB, 4MB, 2GB, nie zwrócił nic. wrzuciłem dane z jednostkami oddzielonymi spacjami, zgadnij - też nic! dane lądują w tablicy "posortowane", ale nie są wrzucone do listboksa - w ostatniej pętli high z length ci się pomyliło. a co z wartościami typu 1,3kB? twój algorytm robi z tym (pomijając nieprawidłowo wymaganą spację (Opi, to też do Ciebie było)) wartość 1,2999999523 kb. w sumie prawie się zgadza. co to jest "kb"? kilobit? do tego użycie masy tablic dynamicznych, setlength w każdej pętli - wiesz jaką to ma wydajność? u mnie - w naklepanym na kolanie algorytmie - zmieniasz string na string[15] i śmiga. u ciebie? i na koniec - robisz kopię wszystkich danych, a to oznacza, że robisz dokładnie to, czego Opi nie chciał.

amatorszczyzna. popraw to, albo usuń, nie chcemy wprowadzać w błąd forumowiczów.

@Opi: mogłeś poczekać, aż wstanę ;-) odesłane. btw - używam gg, numer jest w ustawieniach mojego konta, tak jest trochę łatwiej niż mailem.

0

WitkorDelphi - pamiętasz słowa Linusa Torwaldsa? Jeżeli potrzebujesz więcej niż trzy wcięcia w kodzie - spieprzyłeś go tak czy inaczej...

Opi, sprawdź jeszcze ten kod. Pominąłem w nim upierdliwe sprawdzanie poprawności danych. Bardziej chodzi mi o samą koncepcję programu. Traktuj jak szablon. Opakuj w klasy itp. Pisałem na szybko.
Tak wyglądają itemy:

34,21 kB
527,20 kB
12,01 MB
0 b
6,42 MB
267 B
unit Unit1;

interface

uses
  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
  Dialogs, StdCtrls;

type
  TCompareProc = function(Sender: TListBox; row1, row2: Integer): Integer;
  TSwapProc = procedure(Sender: TListBox; row1, row2: Integer);

  TForm1 = class(TForm)
    ListBox1: TListBox;
    Button1: TButton;
    procedure Button1Click(Sender: TObject);
  private
    { Private declarations }
  public
    { Public declarations }
  end;

var
  Form1: TForm1;

implementation

{$R *.dfm}

function StrToSize(const s: string): Integer;
var
  DelimiterPos :Integer;
  Value, Coeff :Single;
  CoeffPart    :string;
begin
  DelimiterPos := Pos(' ', s);
  Value := StrToFloatDef(Copy(s, 1, DelimiterPos-1), -1);
  CoeffPart := AnsiUpperCase(Copy(s, DelimiterPos+1, Length(s)));

  if CoeffPart = 'B' then Coeff := 1
     else
  if CoeffPart = 'KB' then Coeff := 1024
     else
  if CoeffPart = 'MB' then Coeff := 1024*1024
     else
  if CoeffPart = 'GB' then Coeff := 1024*1024*1024
     else
     Coeff := -1;

  if (Value = -1) or (Coeff = -1) then
     Result := -1 else Result := Round(Value * Coeff);
end;

/////////////////////////////////////////////////////////////////////////////

function CompareInt(v1, v2 :Integer) :Integer;
begin
  if v1 > v2 then Result := 1;
  if v1 = v2 then Result := 0;
  if v1 < v2 then Result := -1;
end;

/////////////////////////////////////////////////////////////////////////////

function NumCompareProc(Sender: TListBox; row1, row2: Integer): Integer;
begin
  with Sender do
  begin
    Result := CompareInt(StrToSize(Items[row1]), StrToSize(Items[row2]));
    if Result <> 0 then
    begin
      if (Items[row1] = '') then Result := 1
         else
      if (Items[row2] = '') then Result := -1
    end
    else
      Result := row1 - row2;
  end;
end;

/////////////////////////////////////////////////////////////////////////////

procedure SwapProc(Sender: TListBox; row1, row2: Integer);
var
  s: string;
begin
  with Sender do begin
    s := Items[row1];
    Items[row1] := Items[row2];
    Items[row2] := s;
  end;
end;

/////////////////////////////////////////////////////////////////////////////

procedure QuickSort(var ListBox :TListBox; bottom, top: Integer; Compare: TCompareProc; Swap: TSwapProc);
var
  up, down, pivot: integer;
begin
  down := top;
  up := bottom;
  pivot := (top + bottom) div 2;

  repeat
    while compare(ListBox, up, pivot) < 0 do Inc(up);

    while compare(ListBox, down, pivot) > 0 do Dec(down);

    if up <= down then
    begin
      swap(ListBox, up, down);
      if pivot = up then pivot := down
         else
      if pivot = down then pivot := up;
      Inc(up);
      Dec(down);
    end;
  until up > down;

  if bottom < down then
    quickSort(ListBox, bottom, down, compare, swap);

  if up < top then
    quickSort(ListBox, up, top, compare, swap);
end;

/////////////////////////////////////////////////////////////////////////////

procedure Sort(var ListBox :TListBox; Compare: TCompareProc; Swap: TSwapProc);
begin
  if not Assigned(Compare) then Compare := NumCompareProc;
  if not Assigned(Swap) then Swap := SwapProc;
  QuickSort(ListBox, 0, ListBox.Items.Count-1, Compare, Swap);
end;

/////////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////

procedure TForm1.Button1Click(Sender: TObject);
var
  C :TCompareProc;
  S :TSwapProc;
begin
  C := NumCompareProc;
  S := SwapProc;

  Sort(ListBox1, C, S);
end;

end.
0

to chyba dzień na czepianie się cudzego kodu...

function StrToSize(const s: string): Integer;
if CoeffPart = 'GB' then Coeff := 1024*1024*1024
Result := Round(Value * Coeff);

coś mi mówi, że to się skończy wyjątkiem. w compareint zjadłeś dwa else. co, jeśli nie ma spacji przed jednostką (w prawidłowym zapisie nie powinno być), albo jest przecinek zamiast kropki?
idea taka sama jak u mnie...

0

To moze takie moje pytanie... Jesli moge Drogi Moderatorze :)
Skad sie biora te dane o rozmiarach? Bo moze sa generowane jakims algorytmem i kropka oraz spacja zawsze jest? Czy sa wpisywane przez uzytkownika?

0

Ogólnie to nie miałem zamiaru się czepiać nikogo/niczego. Fakt ŁF, twój kod jest nieco odporniejszy na błędy. Ja pominąłem jakąkolwiek walidacje bo nie wiem co owe itemy generuje. Niech Opi sobie zakoduje. Kod dałem tylko po to aby mógł sobie wybrać troszkę z mojego, troszkę z Twojego.

Jeśli o mnie chodzi to owe potyczki na kod traktuję na zasadzie [browar] . A 25 zł to najlepiej na Wielką orkiestrę świątecznej pomocy. Opi pomógł mi kiedyś bardziej niż się spodziewa - oddałem pomoc ;-)

I odpowiedź na drugie pytanie autora - musisz sortować numerycznie a nie tekstowo wtedy 2 będzie przed 10

0

Już po wszystkim :)

Co do przecinka czy spacji.
Te dane generuje automatycznie, więc zawsze jest przecinek i zawsze jest spacja.
Spacja ułatwia zadanie dla kolumny z tekstem i liczbą (1 plik, 2 pliki).

Dziękuję za zainteresowanie tematem.

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