🙏 Helfen Sie jetzt mit, unser LibreOffice Forum zu erhalten! 🙏
Mit Ihrer Spende sichern Sie den Fortbestand, den Ausbau und die laufenden Kosten dieses Forums. 🌱

🍀 Jeder Beitrag zählt – vielen Dank für Ihre Unterstützung!🍀

❤️ DANKE >> << DANKE ❤️

>> Dank Ihrer Unterstützung -> Keine Werbung für alle registrierten LibreOffice-Forum User! <<
🤗 Als Dankeschön werden Sie im Forum als LO-SUPPORTER gekennzeichnet. 🤗

[gelöst] Arrays als ByValue übergeben

Alles zur Programmierung im LibreOffice.
Antworten
Protactinium
Beiträge: 3
Registriert: Sa 26. Sep 2015, 16:45

[gelöst] Arrays als ByValue übergeben

Beitrag von Protactinium » Sa 26. Sep 2015, 17:23

Ich habe eine Feldsortierprozedur aus einer MS Office Datei übernommen, die dort fehlerfrei funktioniert.
Mit unten stehendem Code habe ich getestet und festgestellt, dass zwar eine Reihenfolge oder das sortierte Feld ausgegeben wird,
jedoch scheinbar auch das Originalfeld mitsortiert wird.

Code: Alles auswählen

Sub test
dim K (4) as integer
dim Z(4) as integer
K(0) = 10
K(1) = 9
K(2) = 8
K(3) = 7
K(4) = 15
Z =  fc_Sortieren(K,0,1)
end sub


Function fc_Sortieren(ByRef sortfeld As Variant, pruefdimension%, Sortiervariante As Integer) As Variant
Dim X As Variant, Ergebnisfeld As Variant, X2 As Variant
...
 Select Case Sortiervariante
         Case 1: ' Das übergebene Feld wird nicht sortiert - Ausgabe einer Sortierreihenfolge
                   X = sortfeld
                   fc_Sortieren = fc_Sortieren_X(X, pruefdimension, Dimension, True)
         ....     
              
An dieser Stelle erwarte ich eigentlich, dass eine Kopie der Feldvariablen (K = byRef von sortfeld) übergeben wird.

Allerdings werden in der nachfolgenden Funktion

Code: Alles auswählen

         
Function fc_Sortieren_X(ByRef sortfeld As Variant, pruefdimension%, Dimension As Integer, IDfeldausgabe As Boolean) As Variant
...
Dim IDfeld() As Integer

<sortfeld und IDfeld werden bearbeitet>
...
<>
If IDfeldausgabe Then  fc_Sortieren_X = IDfeld
immer alle Variablen gleichzeitig verändert (also K;X(aus fc_Sortieren) und sortfeld (aus fc_sortieren_X).
Z erhält zwar korrekterweise die ID Reihenfolge (also Z(0) = 4...) jedoch ist K(0) = 15
Selbst, wenn ich statt X = sortfeld

Code: Alles auswählen

Function fc_Wert (byval XY as variant) as variant
	fc_Wert = XY
end function
einbaue, werden immer alle Variablen mitverändert. Auch eine Namensänderung der Variablen hilft nicht.

Ist das ein BUG?
Wie kann ich es erreichen, dass nur eine Kopie des Feldes an die untergeordnete Sortierfunktion übergeben wird?
Ein ByVal als Prozedurübergabewert muss leider ausfallen, da die Funktion (eigentlich) beides kann:
Felder sortieren und das Originalfeld unangetastet lassen.
Zuletzt geändert von Protactinium am Mi 30. Sep 2015, 13:43, insgesamt 1-mal geändert.

gogo
* LO-Experte *
Beiträge: 1081
Registriert: Sa 5. Feb 2011, 19:07

Re: Arrays als ByValue übergeben

Beitrag von gogo » So 27. Sep 2015, 14:27

Arrays sind Objekte, und die können per Definition NICHT byVal übergeben werden.
Wie aus dem Code unten ersichtlich (einfach die "main" ausführen), verhalten sich Objekte und Variablen ganz anders. Du kannst auch nicht die Objektvariable in einer andern speichern ("xO=x"), diese Zuweisung macht auch eine Übergabe ByRef!, lediglich ein Duplizieren aller Teilwerte des Objektes ("xC(0)=x(0) etc.") funktioniert!
... und der ByVal Aufruf muss (glaub' ich) im Aufruf der Funktion stehen, nicht in der Funktionsdefinition.

Code: Alles auswählen

REM  *****  BASIC  *****
option explicit
sub main
'dim x(0) as integer
'dim x(0) as object
dim x(0)' as variant
dim xO as object
dim xC(0)
dim y, yO
x(0)="x-original"
xO=x
xC(0)=x(0)

y="y-original"
yO=y

	msgbox "Ausgangswerte:" & chr(13) & "x: " & x(0) & chr(13) & "xO: " & xO(0) & chr(13) & "yC: " & xC(0) & chr(13) & chr(13) & "y: " & y  & chr(13) & "yO: " & yO

	manipulateX(byval x)
'	manipulateX(byval xO)
	manipulateY(byval y)
	msgbox "Uebergabe ByVal:" & chr(13) & "x: " & x(0) & chr(13) & "xO: " & xO(0) & chr(13) & "yC: " & xC(0) & chr(13) & chr(13) & "y: " & y  & chr(13) & "yO: " & yO
	
	manipulateX(x)
	manipulateY(y)
	msgbox "Uebergabe ByRef (ohne Parameter):" & chr(13) & "x: " & x(0) & chr(13) & "xO: " & xO(0) & chr(13) & "yC: " & xC(0) & chr(13) & chr(13) & "y: " & y  & chr(13) & "yO: " & yO

end sub

function manipulateX(x)
	x(0)="x-veraendert"
end function

function manipulateY(y)
	y="y-veraendert"
end function
g
2008 LucidL./MaverickM./WinXP LibreOffice 3.3.2 > 02/13 LinuxMint13/Xubuntu > 09/13 Debian Wheezy+LO3.5.4.2 > 01/15 Debian Jessie KDE+LO4.3.3.2/Mint17 openbox auf USB+LO4.2.8.2 > 03/16 ArchLin & LO5.1+ff > 02/18 Kubuntu

Protactinium
Beiträge: 3
Registriert: Sa 26. Sep 2015, 16:45

Re: Arrays als ByValue übergeben

Beitrag von Protactinium » So 27. Sep 2015, 18:02

Danke gogo.
Das habe ich verstanden. Jetzt versuche ich seit einiger Zeit die Prozedur so umzubauen, dass genau das Kopieren passiert.
Da ich jedoch die Dimension des übergebenen Feldes nicht kenne, wollte ich eine Schleife bauen.

Code: Alles auswählen

...
On Error GoTo Planfehler:
    i = 0
    Do While True:
        i = i + 1
        tmp = UBound(sortfeld, i)        
    Loop
Planfehler:
    Dimension = i - 1
On Error GoTo 0
Print  "... das übergebene Feld hat " & Dimension & " Dimensionen"

' Anpassung LibreOffice
	Dim Feldkopie as variant
	If Dimension = 1 then
	   Redim Feldkopie(LBOUND(sortfeld()) to UBOUND(sortfeld()))
	   for i = 0 to tmp
	   		Feldkopie(i) = sortfeld(i)
	   next
	else
	   dim l as string
	   For tmp = 1 to Dimension
	      if tmp >1 then l = l &","	
     	  l = l & LBOUND(sortfeld(),tmp)& " to " & UBOUND(sortfeld(),tmp)
	   next	   
	   'PRINT 	l
	   Redim Feldkopie (l)
 	   ...
	end if
Ich bekomme es einfach nicht hin, dass das neue Feld entsprechend dimensioniert wird.
Laut Beobachter handelt es sich bei dem Wert der übergeben werden muss um ein Array (sortfeld Typ = Integer(0 to 4,0 to 1...)
Das Problem scheint das Komma zu sein, das die einzelnen Einträge trennt.
Ich habe jetzt die Dokumentation und die Foren gewälzt, um noch andere Varianten zu finden, z.B. Zuordnung von Array(2,3,3) und Ähnliches, aber bisher noch nichts brauchbares gefunden.Da ich nicht für jede Dimension eine einzelne Schleife bauen wollte, würde mich schon interessieren, wie ich die Zuordnung redim Feldkopie (l) so hinbekomme, dass ich die Dimensionen dynamisch bestimmen kann?
Bzw. Gibt es hierzu einen ensprechenden Datentyp?
Ich habe in der API Dokumentation geschaut, aber das http://api.libreoffice.org/docs/cpp/ref/a00051.html übersteigt dann doch meine momentanen Fähigkeiten.

Benutzeravatar
karolus
* LO-Experte *
Beiträge: 2539
Registriert: Fr 10. Dez 2010, 10:01

Re: Arrays als ByValue übergeben

Beitrag von karolus » So 27. Sep 2015, 21:57

Hallo

Ich weiss nicht so recht was du mit deiner Sortiererei in Basic eigentlich bewerkstelligen möchtest --

in Python hast du Prinzip exakt zwei Möglichkeiten:

entweder die Methode `.sort()` auf Listen-objecten die die Liste selbst sortiert und None zurückgibt.
CodeBeispiel:

Code: Alles auswählen

some_list = [10, 9, 8, 14, 5]
print( somelist.sort())
>> None #das ist die Rückgabe
print(some_list)
>> [5, 8, 9, 10, 14] #hier ist die veränderte Liste   
oder du nimmst die Function sorted(...) die eine sortierte Liste aus beliebigen ContainerObjecten zurückgibt

Code: Alles auswählen

something = ( 10, 9, 8, 14, 5) #das zb ist ein tuple
print( sorted( something ))
>> [5, 8, 9, 10, 14] #die Rückgabe
print(something)
>> (10, 9, 8, 14, 5) #der ursprüngliche tuple unverändert   
LO7.4.7.5 debian 12(bookworm) auf Raspberry4b 8GB (64bit)
LO24.8.0.3 flatpak debian 12(bookworm) auf Raspberry4b 8GB (64bit)

gogo
* LO-Experte *
Beiträge: 1081
Registriert: Sa 5. Feb 2011, 19:07

Re: Arrays als ByValue übergeben

Beitrag von gogo » So 27. Sep 2015, 22:50

Untenstehende Funktion liefert die Dimension des eines x-beliebigen Arrays (klappert ggf. 61 Dimensionen ab - mehr als 4 sind's aber eh nie, außer bei Programmierern mit sehr sehr hohen IQs ;) )

Code: Alles auswählen

Function TOOL_ArrayHatXDimensionen(aArray) As Integer
'Rueckgabewert 0 wenn kein Array, eins bis x wenn doch eines...
Dim lLB as long
Dim x

  if not isarray(aArray) then
	x = 1
  else

    on ERROR goto RAUSDA

	  for x = 1 To 61 
	   lLB = lbound(aArray, x) 
		if Err <> 0 then exit for 
	  next x
  end if

rausda:

TOOL_ArrayHatXDimensionen = x - 1 
end function
Dann musst Du nur noch mit ubound die Größe der Dimension abfragen, é voilà.
also für das unbekannte arrayX

Code: Alles auswählen

nDIMs=TOOL_ArrayHatXDimensionen(arrayX)
dim UboundsY(nDIMs)
for n = 1 to (nDIMs + 1)
	UboundsY(n) = ubound(arrayX, n)
next n
Eine variable Deklarationsanweisung ist mir aber nicht bekannt, d.h. Du musst eine lange Case-Anweisung schreiben, in der die möglichen Dimensionen vorkommen:

Code: Alles auswählen

dim arrayY(nDIMs)
select case nDIMs
case 0
	' KEIN ARRAY!
case 
	redim arrayY(UboundsY(1))
case 
	redim arrayY(UboundsY(1), UboundsY(2))
case 
	redim arrayY(UboundsY(1), UboundsY(2), UboundsY(3))
case 
	redim arrayY(UboundsY(1), UboundsY(2), UboundsY(3), UboundsY(4))
case 
	redim arrayY(UboundsY(1), UboundsY(2), UboundsY(3), UboundsY(4), UboundsY(5))
case else
	msgbox "Es werden nur bis zu 5-dimensionale Arrays unterstuetzt!"
end select
	
... und dann natürlich das Befüllen ...
g
2008 LucidL./MaverickM./WinXP LibreOffice 3.3.2 > 02/13 LinuxMint13/Xubuntu > 09/13 Debian Wheezy+LO3.5.4.2 > 01/15 Debian Jessie KDE+LO4.3.3.2/Mint17 openbox auf USB+LO4.2.8.2 > 03/16 ArchLin & LO5.1+ff > 02/18 Kubuntu

Protactinium
Beiträge: 3
Registriert: Sa 26. Sep 2015, 16:45

Re: Arrays als ByValue übergeben

Beitrag von Protactinium » Mi 30. Sep 2015, 13:41

Karolus
- > Ich will einen A* Wegfindungsalgorythmus (zu Anschaungszwecken) visualisieren. Dazu muss ich eigentlich ständig 3 bis 5 dimensionale Listen sortieren. D.h. ich brauche ständig Listen (alle Dimensionen) sortiert bzw. die Reihenfolge der Sortierung, damit ich anhand dieser Reihenfolge Werte aus den einzelnen Dimensionen in das Tabellenblatt schreiben kann.
Da das ein privates Projekt mache ich das im LibreOffice. Auf Arbeit habe ich eine Funktion im VBA die Felder sortiert, die ich jetzt anpassen wollte.
Ich schaue mir mal den Lösungsansatz von dir an. Das könnte eine Lösung sein.
Gogo ->
Den von dir beschriebenen Weg bin ich bereits gegangen. Ich bestimme die Dimensionalität des Feldes und dann überrnehme ich die Werte.
Ich habe hier bereits einen guten Algorythmus gehabt und wollte auf das Bauen für jede einzelne Dimension verzichten, auch wenn es meistens nur 2 sind, da gebe ich euch recht.

Ich denke, dass das Problem als gelöst gelten kann.
Byvals von feldern sind im Libre Office nicht möglich und auch eine Felddefinition per variablem Textparameter ist nicht bekannt.
Möglicherweise kann man mt der Sorted Funktion arbeiten. -> In der nächsten Spätschicht schaue ich mir das einmal an und versuche meine Prozedur (von der ein Teil so ähnlich wie die Sorted Funktion funktioniert) umzubauen. Das Ergebnis stelle ich dann hier zur Verfügung.
-

gogo
* LO-Experte *
Beiträge: 1081
Registriert: Sa 5. Feb 2011, 19:07

Re: Arrays als ByValue übergeben

Beitrag von gogo » Do 1. Okt 2015, 18:23

Pedanterie an:
gogo hat geschrieben:... lediglich ein Duplizieren aller Teilwerte des Objektes ("xC(0)=x(0) etc.") funktioniert! ...
... leider nicht, falls der Teilwert ein Objekt ist, geht's wieder nicht :oops:
Pedanterie aus:
g
2008 LucidL./MaverickM./WinXP LibreOffice 3.3.2 > 02/13 LinuxMint13/Xubuntu > 09/13 Debian Wheezy+LO3.5.4.2 > 01/15 Debian Jessie KDE+LO4.3.3.2/Mint17 openbox auf USB+LO4.2.8.2 > 03/16 ArchLin & LO5.1+ff > 02/18 Kubuntu


An alle, die das LibreOffice-Forum gern nutzen und unterstützen wollen:


Bitte helfen Sie uns mit 7 Euro pro Monat.
Durch Ihren Beitrag tragen Sie dazu bei, unsere laufenden Kosten für die kommenden Monate zu decken.
Unkompliziert per Kreditkarte oder PayPal.
Als ein kleines Dankeschön werden Sie im LO-Forum als SUPPORTER gekennzeichnet.



Antworten