Delphi-PRAXiS

Delphi-PRAXiS (https://www.delphipraxis.net/forum.php)
-   Sonstige Fragen zu Delphi (https://www.delphipraxis.net/19-sonstige-fragen-zu-delphi/)
-   -   Elegante Lösung gesucht, 3 Boolean-Werte, nur einer darf gesetzt sein (https://www.delphipraxis.net/188339-elegante-loesung-gesucht-3-boolean-werte-nur-einer-darf-gesetzt-sein.html)

hoika 22. Feb 2016 16:09

Elegante Lösung gesucht, 3 Boolean-Werte, nur einer darf gesetzt sein
 
Hallo,

3 Variablen
Delphi-Quellcode:
var
  B1, B2, B3: Boolean;
  bOK: Boolean;
begin
  //
  bOK := ??
end;
bOK soll jetzt nur True sein, wenn nur einer der 3 Werte True ist.
Mein bisheriger Ansatz:

Delphi-Quellcode:
bOK := False;
if B1 then
begin
  bOK := True;
end;
if B2 then
begin
  if bOK then
  begin
    bOK := False;
    Exit;
  end;
  bOK := B2;
end;
if Be then
begin
usw.

Irgendwie ist heute Montag ...

Wie löst man das eleganter ???

Ich will nicht viele And's und Or's haben.

Delphi-Quellcode:
  if ((B1=True) and (B2=False) and (B3=False)) or
     ((B1=False) and (B2=True) and (B3=False)) or
     ((B1=False) and (B2=False) and (B3=True)) then
  begin
    bOK := True;
  end;
Naja, jetzt habe ich halt doch and's und or's ...


Heiko

Luckie 22. Feb 2016 16:17

AW: Elegante Lösung gesucht, 3 Boolean-Werte, nur einer darf gesetzt sein
 
Mit einer OR Verknüpfung?

Delphi-Quellcode:
bOK := B1 or B2 or B3;

TiGü 22. Feb 2016 16:19

AW: Elegante Lösung gesucht, 3 Boolean-Werte, nur einer darf gesetzt sein
 
Delphi-Quellcode:
bOK := B1 xor B2 xor B3;

Luckie 22. Feb 2016 16:39

AW: Elegante Lösung gesucht, 3 Boolean-Werte, nur einer darf gesetzt sein
 
Warum XOR?

Ah ja. Stimmt. Hast Recht. Bei mir wäre bOK auch wahr, wenn zwei oder drei wahr wären, es darf aber nur einer wahr sein.

p80286 22. Feb 2016 16:43

AW: Elegante Lösung gesucht, 3 Boolean-Werte, nur einer darf gesetzt sein
 
Delphi-Quellcode:
w:=0;
if B1 then inc(w,1);
if B2 then inc(w,1);
if B3 then inc(w,1);
bok:=W=1;
Gruß
K-H

hoika 22. Feb 2016 16:46

AW: Elegante Lösung gesucht, 3 Boolean-Werte, nur einer darf gesetzt sein
 
Hallo,
ja, mit dem Inc und Hochzählen sieht elegant aus ;)
Da kommt man nach 17:00 nicht drauf ... ;)

Ah so: elegant und trotzdem leserlich sollte es sein.

Jetzt schmeisse ich mal den Profiler an und mal schaun, was am schnellsten bei 1.000.000 Vergleiche ist.


Danke


Heiko

SProske 22. Feb 2016 16:52

AW: Elegante Lösung gesucht, 3 Boolean-Werte, nur einer darf gesetzt sein
 
Zitat:

Zitat von TiGü (Beitrag 1330995)
Delphi-Quellcode:
bOK := B1 xor B2 xor B3;

Ergibt für 3mal True wieder True ;)



Zitat:

Zitat von p80286 (Beitrag 1331003)
Delphi-Quellcode:
w:=0;
if B1 then inc(w,1);
if B2 then inc(w,1);
if B3 then inc(w,1);
bok:=W=1;
Gruß
K-H

Könnte man auch schreiben als

Delphi-Quellcode:
bOK := IfThen(B1, 1, 0) + IfThen(B2, 1, 0) + IfThen(B3, 1, 0) = 1;

p80286 22. Feb 2016 16:54

AW: Elegante Lösung gesucht, 3 Boolean-Werte, nur einer darf gesetzt sein
 
Zitat:

Zitat von hoika (Beitrag 1331004)
Hallo,
ja, mit dem Inc und Hochzählen sieht elegant aus ;)
Da kommt man nach 17:00 nicht drauf ... ;)

Hmm, übersichtlich, ja als Array..
(Das XOR "gefällt" mir besser. -- Shit nicht zu ende gedacht)
(kommt wohl darauf an mit welchen Hilfskonstruktionen man zuerst gearbeitet hat)

Laß mal hören was effektiver ist.

Gruß
K-H

HeZa 22. Feb 2016 17:13

AW: Elegante Lösung gesucht, 3 Boolean-Werte, nur einer darf gesetzt sein
 
Für den Datentype Boolean (WordBool ausgenommen) funktioniert folgendes:
Delphi-Quellcode:
bOk := Ord(b1) +Ord(b2) +Ord(b3) = 1
Ich ergänze:
Wenn man so etwas wie
Delphi-Quellcode:
b1 := Boolean(11);
macht wird es auch hässlich. :-)

Sir Rufo 22. Feb 2016 18:41

AW: Elegante Lösung gesucht, 3 Boolean-Werte, nur einer darf gesetzt sein
 
Zitat:

Zitat von HeZa (Beitrag 1331014)
Für den Datentype Boolean (WordBool ausgenommen) funktioniert folgendes:
Delphi-Quellcode:
bOk := Ord(b1) +Ord(b2) +Ord(b3) = 1
Ich ergänze:
Wenn man so etwas wie
Delphi-Quellcode:
b1 := Boolean(11);
macht wird es auch hässlich. :-)

Korrekter wäre die Form
Delphi-Quellcode:
bOk := Ord( b1 ) + Ord( b2 ) + Ord( b3 ) = Ord( true );
:stupid:

Darlo 22. Feb 2016 20:13

AW: Elegante Lösung gesucht, 3 Boolean-Werte, nur einer darf gesetzt sein
 
Zitat:

Zitat von hoika (Beitrag 1331004)
Ah so: elegant und trotzdem leserlich sollte es sein.

Dann
Zitat:

Zitat von p80286 (Beitrag 1331003)
Delphi-Quellcode:
w:=0;
if B1 then inc(w,1);
if B2 then inc(w,1);
if B3 then inc(w,1);
bok:=W=1;
Gruß
K-H

als assembler code und
Delphi-Quellcode:
{Assembler-Code macht folgendes:
w:=0;
if B1 then inc(w,1);
if B2 then inc(w,1);
if B3 then inc(w,1);
bok:=W=1;}
drüber ;-)

TiGü 22. Feb 2016 20:48

AW: Elegante Lösung gesucht, 3 Boolean-Werte, nur einer darf gesetzt sein
 
Zitat:

Zitat von SProske (Beitrag 1331007)
Zitat:

Zitat von TiGü (Beitrag 1330995)
Delphi-Quellcode:
bOK := B1 xor B2 xor B3;

Ergibt für 3mal True wieder True ;)

Das kann man ja mit einer einfachen if-Abfrage vorher prüfen.

BenjaminH 22. Feb 2016 21:01

AW: Elegante Lösung gesucht, 3 Boolean-Werte, nur einer darf gesetzt sein
 
Zitat:

Zitat von TiGü (Beitrag 1331029)
Das kann man ja mit einer einfachen if-Abfrage vorher prüfen.

oder ;)
Delphi-Quellcode:
bOK := (B1 xor B2 xor B3) and not (B1 and B2 and B3);

Delphi-Laie 22. Feb 2016 22:51

AW: Elegante Lösung gesucht, 3 Boolean-Werte, nur einer darf gesetzt sein
 
Zitat:

Zitat von BenjaminH (Beitrag 1331030)
Zitat:

Zitat von TiGü (Beitrag 1331029)
Das kann man ja mit einer einfachen if-Abfrage vorher prüfen.

oder ;)
Delphi-Quellcode:
bOK := (B1 xor B2 xor B3) and not (B1 and B2 and B3);

Das ist elegant! So etwas suchte ich auch, fand es aber auf die Schnelle nicht. Zwar werden die drei Variablen zweimal miteinander verknüft (soweit war ich noch(?) nicht), jedoch verbleibt die Lösung des Problems auf dem Niveau boolescher bzw. logischer Operationen (die Addition ist pragmatisch und korrekt, hat aber den zwangsläufigen Nimbus einer Bastelei). Außerdem ist augenblicklich klar, daß diese Funktion für beliebig viele Operanden erweiter- bzw. anwendbar ist (beliebig großes boolesches Array).

Meine Anerkennung!

Uwe Raabe 23. Feb 2016 07:43

AW: Elegante Lösung gesucht, 3 Boolean-Werte, nur einer darf gesetzt sein
 
Zitat:

Zitat von Delphi-Laie (Beitrag 1331036)
Außerdem ist augenblicklich klar, daß diese Funktion für beliebig viele Operanden erweiter- bzw. anwendbar ist (beliebig großes boolesches Array).

Wie würde man das denn jetzt auf vier boolsche Variablen erweitern?

Sir Rufo 23. Feb 2016 07:52

AW: Elegante Lösung gesucht, 3 Boolean-Werte, nur einer darf gesetzt sein
 
Eventuell so?
Delphi-Quellcode:
function IsOneOfThree( const B1, B2, B3: Boolean ): Boolean;
begin
  Result := ( B1 xor B2 xor B3 ) and not ( B1 and B2 and B3 );
end;

function IsOneOfFour( const B1, B2, B3, B4: Boolean ): Boolean;
begin
  Result := IsOneOfThree( IsOneOfThree( B1, B2, B3 ), B4, False );
end;

HeZa 23. Feb 2016 08:20

AW: Elegante Lösung gesucht, 3 Boolean-Werte, nur einer darf gesetzt sein
 
Zitat:

Zitat von Delphi-Laie (Beitrag 1331036)
Zitat:

Zitat von BenjaminH (Beitrag 1331030)
...
oder ;)
Delphi-Quellcode:
bOK := (B1 xor B2 xor B3) and not (B1 and B2 and B3);

Das ist elegant! So etwas suchte ich auch, fand es aber auf die Schnelle nicht. Zwar werden die drei Variablen zweimal miteinander verknüft (soweit war ich noch(?) nicht), jedoch verbleibt die Lösung des Problems auf dem Niveau boolescher bzw. logischer Operationen (die Addition ist pragmatisch und korrekt, hat aber den zwangsläufigen Nimbus einer Bastelei). Außerdem ist augenblicklich klar, daß diese Funktion für beliebig viele Operanden erweiter- bzw. anwendbar ist (beliebig großes boolesches Array).

Meine Anerkennung!

Dem schließe ich mich an.

SProske 23. Feb 2016 09:43

AW: Elegante Lösung gesucht, 3 Boolean-Werte, nur einer darf gesetzt sein
 
Für die beliebige Anzahl an Bool-Werten (Array) würde mir jetzt eher so etwas vorschweben:

Delphi-Quellcode:
function IsOnlyOneTrue(const BoolArr: TArray<Boolean>): Boolean;
var
  I: Integer;
begin
  Result := False;
  for I := Low(BoolArr) to High(BoolArr) do
    if BoolArr[I] then
      if Result then
        Exit(False)
      else
        Result := True;
end;

hoika 23. Feb 2016 10:10

AW: Elegante Lösung gesucht, 3 Boolean-Werte, nur einer darf gesetzt sein
 
Hallo,

nachdem ich den Code gezeigt habe, wurde mir gesagt
"Falsch!", der erste True-Wert wird genommen, egal wie viele True sind ;)


Heiko

Delphi-Laie 23. Feb 2016 10:25

AW: Elegante Lösung gesucht, 3 Boolean-Werte, nur einer darf gesetzt sein
 
Zitat:

Zitat von Uwe Raabe (Beitrag 1331047)
Zitat:

Zitat von Delphi-Laie (Beitrag 1331036)
Außerdem ist augenblicklich klar, daß diese Funktion für beliebig viele Operanden erweiter- bzw. anwendbar ist (beliebig großes boolesches Array).

Wie würde man das denn jetzt auf vier boolsche Variablen erweitern?

Ganz schwierig:

bOK := (B1 xor B2 xor B3 xor B4) and not (B1 and B2 and B3 and B4)

vermutlich aber falsch, wie mir jetzt dämmert, weil das Zwischenergebnis der xor-Operationen ständig alterniert (ich bin jetzt auf die Schnelle zu bequem zum Denken oder Probieren). Es kommt also darauf an, daß die Anzahl der Operanden (un)gerade bleibt. Bei 5 Operanden

bOK := (B1 xor B2 xor B3 xor B4 xor B5) and not (B1 and B2 and B3 and B4 and B5)

sollte es aber wieder stimmen.

Edit: Asche auf mein Haupt, es klappt weder mit 4en noch mit 5en. Ist wohl doch nicht verallgemeinerbar. Schade.

Union 23. Feb 2016 10:39

AW: Elegante Lösung gesucht, 3 Boolean-Werte, nur einer darf gesetzt sein
 
Ich würde auch ein Bool Array vorziehen:
Delphi-Quellcode:
function IsNumberOfValuesSet(const AValues : array of Boolean; AMax : Integer = 1) : Boolean;
var
  LCount : Integer;
begin
  LCount := 0;
  for Result in AValues do
    if Result then
    begin
      Inc(LCount);
      if LCount > AMax then
        Break;
    end;
  Result := LCount = AMax;
end;

begin
  Writeln(IsNumberOfValuesSet([False]));
  Writeln(IsNumberOfValuesSet([False, True]));
  Writeln(IsNumberOfValuesSet([False, True, False]));
  Writeln(IsNumberOfValuesSet([False, True, False, True]));
  Writeln(IsNumberOfValuesSet([False, True, False, True], 2));
  Readln;
end.

himitsu 23. Feb 2016 12:57

AW: Elegante Lösung gesucht, 3 Boolean-Werte, nur einer darf gesetzt sein
 
Delphi-Quellcode:
B1=True
Wobei man das ja eigentlich nicht macht.

Die mathematischen Lösungen mit Ord gehen natürlich nur unter der Annahme, daß man davon ausgeht, daß nur True oder False drin steht.

Wobei True = not False, bzw. True <> "True".
Der Delphi-Boolean kennt ja 254 "True" und ein False, deswegen auch niemals
Delphi-Quellcode:
B1=True
:stupid:

EricMeyer 23. Feb 2016 13:08

AW: Elegante Lösung gesucht, 3 Boolean-Werte, nur einer darf gesetzt sein
 
oder sowas

function CountTrues (ABoolean :array of Boolean):Integer
for i ...
result := result + ((-1)*strtoint(booltostr(ABoolean [i])))

Delphi-Laie 23. Feb 2016 13:12

AW: Elegante Lösung gesucht, 3 Boolean-Werte, nur einer darf gesetzt sein
 
Zitat:

Zitat von himitsu (Beitrag 1331094)
Delphi-Quellcode:
B1=True
Der Delphi-Boolean kennt ja 254 "True" und ein False, deswegen auch niemals
Delphi-Quellcode:
B1=True
:stupid:

Fangen die modernen Delphi-Compiler (so ab Version XEx) diese Programmierschludrigkeit nicht endlich ab? Genaugenommen ist das ja kein Fehler, denn rein von der booleschen Logik ist true=true.

Und das "=true" passiert vermutlich auch so manchem gestandenen Programmierer dann und wann, das ist einfach mental zu aufdringlich. Dito: "=false" anstatt "if not"....

himitsu 23. Feb 2016 13:22

AW: Elegante Lösung gesucht, 3 Boolean-Werte, nur einer darf gesetzt sein
 
Nein, das darf nicht abgefangen werden.

Es kommt auf die "Auswertung an, also ob man es logisch oder binär vergleich ... = ist in Pascal immer "binär".

Nur bei der Typkonvertierung zwischen Boolean/ByteBool/WordBool/LongBool/Variant wird der logische Wert konvertiert.

TiGü 24. Feb 2016 11:38

AW: Elegante Lösung gesucht, 3 Boolean-Werte, nur einer darf gesetzt sein
 
Um das nochmal aufzugreifen:
(~a*~b*c)+(~a*b*~c)+(a*~b*~c) in http://www.elektroniker-bu.de/kvdiagramm.htm reingehauen und sehen, dass die DNF nicht vereinfacht werden kann.
Kannst auch die KNF nehmen ((a+b+c) * (~b+~c) * (~a+~c) * (~a+~b)), aber das bringt dich ja auch nicht wirklich weiter.

Also:
B1 := (not B1 and not B2 and B3) or
(not B1 and B2 and not B3) or
(B1 and not B2 and not B3);

himitsu 24. Feb 2016 13:07

AW: Elegante Lösung gesucht, 3 Boolean-Werte, nur einer darf gesetzt sein
 
Delphi-Quellcode:
if Ord(A) + Ord(B) + Ord(C) <= 1 then
(maximal 1) und
Delphi-Quellcode:
if Ord(A) + Ord(B) + Ord(C) = 1 then
(immer 1)
geht halt nur, wenn wirklich nur True und False drin stehen.
Einen Cast von Boolean auf Byte und zurück macht Delphi immer nur binär.

Es gibt in Pascal keine Möglichkeit zu steuern ob Binär oder Logisch konvertiert wird. (es gibt immer nur je Eines von Beidem)

Delphi-Quellcode:
if Ord(A <> False) + Ord(B <> False) + Ord(C <> False) = {<=} 1 then


Delphi-Quellcode:
NOT
arbeitet bei einem Boolean logisch und nicht binär (glaub ich), also ginge auch
Delphi-Quellcode:
if Ord(not A) + Ord(not B) + Ord(not C) = {>=} 2 {3-1} then

Valle 24. Feb 2016 13:42

AW: Elegante Lösung gesucht, 3 Boolean-Werte, nur einer darf gesetzt sein
 
Wie wäre es, wenn man sich dafür eine Hilfsfunktion baut?

Pseudocode:
Code:
def OneIfTrue(mybool):
    return 1 if mybool else 0

def ExactlyOneIsTrue(b1, b2, b3):
    return OneIfTrue(b1) + OneIfTrue(b2) + OneIfTrue(b2) == 1
Fände ich am elegantesten, solange sich ein Array noch nicht lohnt.

himitsu 24. Feb 2016 13:51

AW: Elegante Lösung gesucht, 3 Boolean-Werte, nur einer darf gesetzt sein
 
Delphi-Quellcode:
OneIfTrue
, bzw.
Delphi-Quellcode:
IfThen(b1, 1, 0)
sollten aber hoffentlich als Inline-Funktion vorliegen.

Jasocul 24. Feb 2016 13:52

AW: Elegante Lösung gesucht, 3 Boolean-Werte, nur einer darf gesetzt sein
 
Wie wäre denn:
Delphi-Quellcode:
b4 := Ord(b1 and True) + Ord(b2 and True) + Ord(b3 and True) = 1;

Valle 24. Feb 2016 14:03

AW: Elegante Lösung gesucht, 3 Boolean-Werte, nur einer darf gesetzt sein
 
Zitat:

Zitat von Jasocul (Beitrag 1331221)
Wie wäre denn:
Delphi-Quellcode:
b4 := Ord(b1 and True) + Ord(b2 and True) + Ord(b3 and True) = 1;

Hast du das mal ausprobiert? Könnte mir vorstellen, dass es wegoptimiert wird.

himitsu 24. Feb 2016 14:04

AW: Elegante Lösung gesucht, 3 Boolean-Werte, nur einer darf gesetzt sein
 
Delphi-Quellcode:
x and True
und
Delphi-Quellcode:
x or False
arbeiten logisch, also ja ...... faaaaaaaaalls der Compiler das nicht "optimiert" und weg lässt. :zwinker:

Jasocul 24. Feb 2016 14:05

AW: Elegante Lösung gesucht, 3 Boolean-Werte, nur einer darf gesetzt sein
 
Ja, ist getestet und hat bei mir funktioniert.
Habe bewusst mit Werten ungleich 1 für die Variablen getestet.

alex517 24. Feb 2016 17:33

AW: Elegante Lösung gesucht, 3 Boolean-Werte, nur einer darf gesetzt sein
 
Zitat:

Zitat von hoika (Beitrag 1330992)
Wie löst man das eleganter ???
Ich will nicht viele And's und Or's haben.

da würde ich diese Varianten bevorzugen
Delphi-Quellcode:
function CountChecked(AValues: Array of Boolean): Integer;
var
  i: Integer;
begin
  Result := 0;
  for I := Low(AValues) to High(AValues) do
    if AValues[i] then inc(Result);
end;
oder
Delphi-Quellcode:
function CountChecked(AValues: Array of Boolean): Integer;
var
  i: Integer;
begin
  Result := 0;
  for I := Low(AValues) to High(AValues) do
    Inc(Result, Ord(AValues[i] <> false));
end;

Aufruf:
Delphi-Quellcode:
  if CountChecked([True, False, Boolean(3), Boolean(0), Boolean(99), Boolean(-1)]) = 1 then
   ...
So kann man beliebig viele Parameter übergeben und hat die Möglichkeit zu entscheiden
wie viele true sein müssen.


Alle Zeitangaben in WEZ +1. Es ist jetzt 15:42 Uhr.

Powered by vBulletin® Copyright ©2000 - 2024, Jelsoft Enterprises Ltd.
LinkBacks Enabled by vBSEO © 2011, Crawlability, Inc.
Delphi-PRAXiS (c) 2002 - 2023 by Daniel R. Wolf, 2024 by Thomas Breitkreuz