Kopiowanie dynamicznej tablicy - wyniku pracy funkcji.

Odpowiedz Nowy wątek
2019-10-08 12:32
0

Witam
Chyba mi ten tytuł nie wyszedł :/
W skrócie :
Mam funkcje która oddaje wynik w formie dynamicznej tablicy rekordów.
Funkcja w swym "ciele" trochę miesza więc nie chciał bym jej zbyt często odpytywać.
I problem :
W procedurze potrzebuje danych z w/w funkcji Więc ją wywołuje i ... musiał bym jakoś sklonować sam wynik tej funkcji - ale jak to zrobić nie znając jej długości, którą muszę znać by utworzyć dynamiczną tablice przetrzymującą ten wynik (jego kopie).

Coś w tym style:

type
dane = record
    dane0:integer;
    dane1:string;
  end;
  dane_ar = array of dane;  

function GetData(argumenty):dane_ar;
 var costam:integer;
    begin
     costam:= jakas_liczba_uzyskana_z_jakichs_operacji; 
     SetLenght(Result,costam);
     for i:=0 to costam do 
        begin
            Result[i].dane0 := jakies_dane0;
            Result[i].dane1 := jakies_dane1;
        end;
end;                                      

procedure KtoraToWykorzystuje();
var 
    kopia : dane_ar;
begin
    kopia:=GetData(argumenty); //????
    // i tu robie coś na tej kopi
end;
pamiętaj że array of ... wymaga ciągłego obszaru pamięci. - _13th_Dragon 2019-10-08 13:58

Pozostało 580 znaków

2019-10-08 12:50
0

Yyy... o ile dobrze rozumiem twój problem, to chyba po prostu umknęło Ci, że oprócz SetLength() do ustawienia rozmiaru dynamicznej tablicy, jest też Length() do odpytania, jaki ma obecnie rozmiar. :D

Pozostało 580 znaków

2019-10-08 13:13
0

@Sensacyjny Sebastian: Ja to wiem - ale to wymagało by dwukrotnego "uruchomienia" tej funkcji - raz by zbadać ilość elementów (dla Lenght) a drugi by znając jej długość wyciągnąć z niej dane. A jak pisałem funkcja "troche miesza" więc nie chce jej co chwila odpalać. Zależy mi by zrobiś to "jednorazowo". Bez użycia zmiennych globalnych (bo to by rozwiązało problem ale nieładnie i mi nie pasuje).

Pozostało 580 znaków

2019-10-08 13:19
0
titako napisał(a):

to wymagało by dwukrotnego "uruchomienia" tej funkcji - raz by zbadać ilość elementów (dla Lenght) a drugi by znając jej długość wyciągnąć z niej dane.

Yyy, że jak? W funkcji GetData() nie operujesz na żadnej zmiennej globalnej, tylko zwracasz tablicę dynamiczną. Tablica dynamiczna przechowuje jakiś z góry ustalony typ i ma długość, którą można zmieniać przez SetLength() oraz ją "wyciągnąć" przez Length(). Po tym, jak w funkcji wołającej zrobisz kopia := GetData(argumenty), możesz zrobić Length(kopia) i to nic Ci nie "namiesza" w tej tablicy. Jak nie chcesz wołać Length() parę razy, to zawsze możesz przypisać tę wartość do zmiennej.

Pozostało 580 znaków

2019-10-08 13:24
0

Wyglądało by to tak:

dlugosc:=Lenght(GetData(argumenty)); // pierwsze wywołanie wnętrza funkcji
SetLenght(kopia,dlugosc);
kopia:=GetData(argumenty); // drugie wywołanie wnętrza funkcji

Czyli wywołam wnętrze funkcji 2 razy - A wnętrze jej jest bazodanowe i gęste od zapytań - więc nie chciał bym budzić smoka dwa razy.

Pozostało 580 znaków

2019-10-08 13:30

Ale zdajesz sobie sprawę, że Result wewnątrz GetData() nie jest statyczne, tzn. jest za każdym razem nową tablicą - i kolejne wywołania zwracają tablice niezależne od siebie?

a := GetData(argumenty);
b := GetData(argumenty);
a[0] := jakas_wartosc;

W takim kodzie zmiana a[0] nie spowoduje zmiany wartości b[0] - tablice są od siebie zupełnie niezależne.


Poza tym - zawsze przecież możesz zrobić:

oryginal := GetData(argumenty);
SetLength(kopia, Length(oryginal));
for i := 0 to Length(oryginal) - 1 do kopia[i] := oryginal[i];
edytowany 4x, ostatnio: furious programming, 2019-10-08 17:34

Pozostało 580 znaków

2019-10-08 13:36
0
kopia:=GetData(argumenty);
dlugosc:=Lenght(kopia);

Ale pamiętaj że następuje kopiowanie wyniku, więc rozważ:

procedure GetData(argumenty;var ret:dane_ar);

Wykonuję programy na zamówienie, pisać na Priv.
Asm/C/C++/Pascal/Delphi/Java/C#/PHP/JS oraz inne języki.

Pozostało 580 znaków

2019-10-08 13:44
1

Ale jestem głupi ! - Moge przepisać dynamiczną tablice bezpośrednio :D. Założyłem z góry że tak łatwo nie będzie. I bez sensu główkowałem. Temat do śmieci :)

Pozostało 580 znaków

2019-10-08 13:54
1

Zastanów się też nad takim rozwiązaniem:

program ideone;

uses sysutils,classes;

type
dane=record
    dane0:integer;
    dane1:string;
end;
dane_ar=array of dane;  

var tb:dane_ar;
var i:Integer;
var tm:TDateTime;
var ts:TStringList;
const str:String='ala ma kota';
const Size:Integer=30000;

begin
    tm:=now;
    SetLength(tb,Size);
    for i:=0 to Size-1 do
    begin
        tb[i].dane0:=i;
        tb[i].dane1:=str;
    end;
    WriteLn(FormatDateTime('nn:ss.zzz',now-tm));

    tm:=now;
    ts:=TStringList.Create;
    for i:=0 to Size-1 do
    begin
        ts.AddObject(str,TObject(Pointer(i)));
    end;
    WriteLn(FormatDateTime('nn:ss.zzz',now-tm));
end.

Wykonuję programy na zamówienie, pisać na Priv.
Asm/C/C++/Pascal/Delphi/Java/C#/PHP/JS oraz inne języki.
edytowany 1x, ostatnio: _13th_Dragon, 2019-10-08 13:55

Pozostało 580 znaków

2019-10-08 14:11
0

@_13th_Dragon: Dzięki - ja podałem czysto przykładowe wnętrze funkcji, tam tego jest więcej i przyszła wielkość tablicy daje się oszacować, a dodatkowo cześć danych będzie przeliczana wiec Tstringlist troche nie pasuje. Ale dzięki ;)

Pozostało 580 znaków

2019-10-08 17:27
0
titako napisał(a):

W procedurze potrzebuje danych z w/w funkcji Więc ją wywołuje i ... musiał bym jakoś sklonować sam wynik tej funkcji - ale jak to zrobić nie znając jej długości, którą muszę znać by utworzyć dynamiczną tablice przetrzymującą ten wynik (jego kopie).

Długość przecież możesz zwrócić za pomocą argumentu w postaci ”ślepej” referencji:

function GetData({tu argumenty wejściowe}, out ACount: Integer): TDataArr;

Funkcja uzupełnia macierz w Result, a na koniec przypisuje jej długość do argumentu ACount. Takie rozwiązanie pozwala uniknąć wielokrotnego wywołania funkcji, tworzenia kopii i innych cudów – dwie pieczenie na jednym ogniu.

Problemem nie jest dobranie konstrukcji nagłówka funkcji, a korzystanie z archaicznych typów danych. Gdybyś dane przechowywał w liście generycznej (np. TFPGList) zamiast w badziewnych tablicach, to zawsze miałbyś dostęp do właściwości Count, zwracającej liczbę rekordów listy. I zamiast zwracać macierz w rezultacie funkcji, mógłbyś uzupełniać listę na podstawie przekazanej w parametrze referencji listy:

procedure FillList({tu argumenty wejściowe}, AList: TDataList);

gdzie TDataList to wyspecjalizowany TFPGList.

Natomiast jeśli potrzebujesz przechowywać pary danych, z czego jedna informacja w parze zawsze ma unikalną wartość, to spokojnie możesz skorzystać z generycznej mapy (np. TFPGMap).


edytowany 6x, ostatnio: furious programming, 2019-10-08 17:32

Pozostało 580 znaków

Odpowiedz
Liczba odpowiedzi na stronę

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