Kann Arrays.stream() auch auf Objekte angewant werden?

  • Themenstarter Themenstarter Gelöschtes Mitglied 56712
  • Beginndatum Beginndatum
G

Gelöschtes Mitglied 56712

Gast
Guten Abend an Alle,
mit folgendem Code erhalte ich ein true resp. false:
Java:
boolean vorhanden = Arrays.stream(new int[]{0, 2, 8, 9}).anyMatch(i -> i == index);
funktioniert mit Integeren werten...

Meine Frage:
kann man das auch mit Strings und Objekten machen?
Was muss ich wie, wo ändern damit es mir z.B. bei einem Objekt auch true oder false zurückgibt?
Was muss hier stehen, damit es funktioniert -> Arrays.stream(new Object[]{ich, du, er, sie}).anyMatch(??? -> ??? == gesucht?)
 
Zuletzt bearbeitet von einem Moderator:
Vielen Dank @httpdigest
Es funktioniert, wenn der/das komplette String/Object vorhanden ist.

Wie könnte man es so hinbekommen, dass ein true zurückgegeben wird sobald ein z.B. i gefunden wird?
Müsste also true zurückgeben bei: ich, sie
Java:
Arrays.stream(new Object[]{ich, du, er, sie}).anyMatch(o -> o equals i)
Das kriege ich mit meinem bescheidenen Wissen nicht gebacken.
Vielen Dank

das i könnte man noch als String parsen.
 
Könnte man nicht mit contains("i") arbeiten?
Wenn man mal davon ausgeht dass es nicht Objects sind sondern Strings sind.
Java:
Arrays.stream(new Object[]{ich, du, er, sie}).anyMatch(o -> o == contains("i"))
Hab es versucht. Aber wie müsste der Code dazu lauten?
 
Wen es Strings sein sollen, dann mach es doch im Code zu Strings:
Arrays.stream(new String[]{"ich", "du", "er", "sie"})

Und bei dem AnyMatch hast Du als Parameter ein Predicate<? super T>. Das Predicate ist ein funktionales Interface, das die Methode test erfordert, die einen Parameter vom Typ T hat und ein boolean zurück gibt.

Und das kann dann ein beliebiger Lambda Ausdruck sein - der halt einen String nehmen muss (Du hast halt einen Stream<String> und damit ist der Typ T halt String) und ein boolean zurück geben muss. Und das kann dann etwas sein wie o -> o.contains("i")

Generell ein paar wichtige Hinweise:
a) Du kannst damit herum spielen! Also nimm Dir die Entwicklungsumgebung Deiner Wahl und spiel einfach herum! Es geht nichts über praktische Erfahrung!
b) Du kannst die Dokumentation ansehen, also z.B.
 
String.lines() kannst du dir auch ansehen. Dann braucht es keinen Umweg über Arrays. Kommt halt auf die Quelle an.
Java:
        """
                ich
                du
                er
                sie"""
                .lines()
                .filter(line -> !line.contains("i"))
                .forEach(System.out::println);
 
@Nouser
ähm...
ich habe ein String[] -Array.
muss ich das jetzt mit einer for Schleife zu einem String umwandeln?
oder wo erweitere ich .lines() ?

Die ArrayList<String[]> xy kann bis zu 1000 oder mehr Einträge haben.
diese durchlaufe ich mit:
Java:
for (String[] s : xy){
    //müsste ich hier jetzt einen String aus <s> erstellen?
}

...bräuchte extrem viel Recourcen.

Trotzdem vielen Dank.
 
Ich denke, es ging um
Arrays.stream(new String[]{"ich", "du", "er", "sie"})

Die Variante, das über ein Literal über mehrere Zeilen zu machen, sieht evtl. etwas eleganter aus.

Aber wenn Du bereits so ein String Array hast, dann wandelst Du das natürlich nicht um in einen mehrzeiligen String um den dann Zeilenweise durchzugehen ...
 
Darf ich nochmals auf diesen Post zurückkommen?
Es wäre für mich jetzt intresannt ob ich auf den INDEX des gefundenen Eintrages kommen könnte.

Wobei allItems ein String[]-Array ist und oT die Zeichenfolge:
Java:
Arrays.stream(allItems).anyMatch(o -> o.toString().startsWith(oT));
obiger Coder gibt mir nur true resp. false zurück...

Fülle eine JComboBox mit allItems:
Java:
comboBox.setModel(new DefaultComboBoxModel(allItems));

JComboBox lässt sich aber nicht wie eine ArrayList mit getIndex(suchSting) (oder so ähnlich) den Index zu ermitteln.
Wie wäre es also möglich anstatt true, den Index des gefundenen Eintrags auszugeben?

Wäre schön wenn das möglich wäre...
Vielen Dank

PS:
Folgender Code dauert bei mehr als 2000 einträgen extem lange!
Vor allem wenn es erst der 2125ister Eintrag ist.
Java:
int index = 0;
for(String s: allItems){
    if(s.startsWith(oT)){
        break;
    }
    index++;
}
system.out.println("Index = "+index)
 
Zuletzt bearbeitet von einem Moderator:
Hat sich erledigt!
Java:
int index = 0;
for(String s: allItems){
    if(s.startsWith(oT)){
        break;
    }
    index++;
}
system.out.println("Index = "+index)
folgendes fehlte im TextFeld:
Code:
ausgabe.setSelectionStart(oT.length());
ausgabe.setSelectionEnd(ausgabe.getText().length());

und das geht jetzt ganz fix...
 
@httpdigest
Vielen Dank! 😀
Es geht mir um die installierten Schriften, welche ich auslesen / verwenden will.

Java:
GraphicsEnvironment gen = GraphicsEnvironment.getLocalGraphicsEnvironment();
String[] allFonts = gen.getAvailableFontFamilyNames();
Diese werden mir in einer JComboBox aufgelistet:
Java:
comboBox.setModel(new DefaultComboBoxModel(allItems));

Aber ich verwende ein JTextField um nach der Schrift zu suchen.
Der Link: https://en.wikipedia.org/wiki/Radix_tree
ist super... aber für einen Anfänger wie ich, einfach zu hoch!

Wie gesagt mit dem Code aus vorhergehendem Post funktioniert es!
Vielen Dank
Richi
 
Mit Streams könnte man den Index etwa so finden:
Java:
int index = IntStream.range(0, entries.size())
        .filter(i -> entries.get(i).startsWith(oT)))
        .findFirst()
        .orElse(-1);
Ich sehe aber keinen wirklichen Vorteil in der Stream-Variante.

Bei deiner Variante musst du aufpassen wenn mal nichts gefunden wird. Der Index wäre dann vermutlich größer als die Liste.
 
@Oneixee5
Vielen Dank hab ich soeben ausprobiert!
Aber iwie dauert das bei mir länger als meine Variante...
Und ja der rest vom Code ist wie immer bei mir nicht optimal und daran könnte es liegen! 😁
Bei deiner Variante musst du aufpassen wenn mal nichts gefunden wird. Der Index wäre dann vermutlich größer als die Liste.
Oder wie bei mir < 0! Aber das kann ich ja abfangen.
Ist eben ein anderer konzeptueller Ansatz und in der heutigen Zeit richtiger.
Welcher wäre jetzt in der heutigen Zeit richtiger?
Der von

Oneixee5​

oder so wie ich es gemacht habe?
Habe das jetzt nicht begriffen...

Trotzdem vielen Dank
es hat geholfen.
Richi
 
Die Variante mit dem Stream ist imho nicht besser, da der Zugriff - jedes mal neu über den Index vermutlich nicht so optimal ist. Deine Variante über den Iterator dürfte etwas schneller sein. Am Ende sind das Implementierungsdetails der JVM.Wir reden hier aber über einen Bereich der Geschwindigkeit, welcher von Menschen nicht wahrgenommen werden kann. Deine Liste dürfte auch nicht so lang sein, dass ein spürbarer Geschwindigkeitsunterschied feststellbar ist. Grundsätzlich ist lesbarer und verständlicher Code immer am Besten. Ob nun per Stream-Api oder Iterator ist zweitrangig. Die Stream-Api passt besser zum Gesamtbild wenn man eher funktional programmiert aber produziert mehr Garbage. Beides ist OK und legitim, alles weitere fällt in den Bereich der Mikrooptimierungen - das sollte man einfach dem Compiler überlassen. Optimierung ist die Wurzel allen Übels ... 😉
 
Also Tobias (Baubär) meint, dass Streams generell besser sind. Das zeigen auch ältere Posts von ihm, wo irgendwelche komplexen Stream-Lösungen gebaut und für gut befunden wurden. Code muss lesbar sein und es macht schlicht keinen Sinn, auf Zwang irgend was mit Streams abzubilden. Effective Java hatte da als Beispiel die Erstellung eines Streams nur um dann forEach aufzurufen meine ich.

Was mir an Deiner Lösung etwas missfällt ist die Trennung vom index von der Schleife. Das ist zwar schön kompakt, aber wenn der Code aus irgend einem Grund aufgebläht wird und dann index noch irgendwie zusätzlich angepasst würde, dann wäre es blöd.

Zugriff über den Index sollte auch unproblematisch sein, wenn es ein String Array ist. Aber ich frage mich gerade, wieso da ein Durchgehen von 2000 Strings irgendwie dauern soll. So ein startsWith ist nicht so aufwändig und sollte schnell gehen. Daher wäre hier wichtig:
a) was genau dauert extrem lange?
b) was bedeutet "extrem lange"?

Im Augenblick zweifle ich etwas, dass es problematisch ist, 2000 Strings mit starts with zu prüfen.
 
Nur um mal zu schauen, was so String Operationen dauern, habe ich einfach mal etwas zusammen gebaut:
Java:
    public static void main(String[] args) {
        long startZeit = System.nanoTime();
        String[] testStrings = new String[4000];
        for (int i = 0; i < testStrings.length; i++) {
            testStrings[i] = UUID.randomUUID().toString();
        }

        for (int i = 0; i < testStrings.length; i++) {
            testStrings[i] = testStrings[i] + " " + testStrings[i].startsWith("1234567890");
        }
        long stopZeit = System.nanoTime();
        System.out.println("Zeit: " + (stopZeit - startZeit) / 1_000_000);
    }

Hier wird nicht nur startsWIth ausgeführt sondern wir haben auch die Initiaisierung mit UUID Strings (was besseres ist mir so auf Anhieb nicht eingefallen) und dann die Veränderung jedes Eintrages in der Messung enthalten. Und das läuft auf meinen M1 MacBook Pro in ca. 39ms.

Im Rahmen eine UI ist das eine Zeit, die kaum zu merken ist als einmalige Aktion - auf jeden Fall ist das in einer UI nichts, das ich als "extrem lange" bezeichnen würde.

Das nur um mein Bauchgefühl bezüglich der Angabe etwas zu belegen / zu verdeutlichen.
 
Im Augenblick zweifle ich etwas, dass es problematisch ist, 2000 Strings mit starts with zu prüfen.
lol, ich auch.

Es geht mir um die installierten Schriften, welche ich auslesen / verwenden will.
Die Schriftarten wirst Du ja sowieso sortiert nach Name anzeigen, d. h. das Array allFonts ist sortiert. Insofern kann man hier auch einfach eine binäre Suche bemühen, wenn man die Suche tatsächlich beschleunigen möchte.

Java:
public int indexOfMatch(String prefix) {
    int ix = Arrays.binarySearch(allFonts, prefix);
    if (ix >= 0) {
        return ix;
    }

    int candidate = -(ix + 1);
    if (candidate < allFonts.length && allFonts[candidate].startsWith(prefix)) {
        return candidate;
    }
    return -1;
}
Ob sich das bei 2000 Zeilen rentiert, sei mal dahingestellt.
 
sucht mit Prefix? Fehlt da nicht ein Comparator mit substring oder so?
Jein.

Nehmen wir mal das Array {"Arial", "Arial Bold", "Courier New", "Times New Roman"}.

binarySearch liefert im Fall eines (exakten) Treffers einfach den Index des gesuchten Elements (Zeilen 3 bis 5 im Code). Suchen wir also nach "Courier New", erhalten wir als Ergebnis eine 2.

Ansonsten liefert binarySearch als Ergebnis indirekt den Index, an der sich das gesuchte Element befinden müsste. Der korrekte Index wird in Zeile 7 berechnet. Suchen wir also z. B. nach "Times", dann müsste sich das Element an Index 3 befinden, binarySearch liefert in dem Fall -4 und in Zeile 7 wird der korrekte Index (die 3) berechnet und als candidate bezeichnet.

Das Element an diesem Index (candidate) im Array muss zwangsweise größer sein als das gesuchte Element. Es kann mit dem gesuchten Präfix beginnen, muss aber nicht. Das wird dann in Zeile 8 geprüft.
 
Ja sorry, das meine Frage so kurz war. Mir ist klar wie es funktioniert. Nur fehlt mir irgendwie die Garantie, dass der zurückgelieferte negative Index richtig ist. Ich habe mir noch mal die Api von String, binarySearch usw. angeschaut. Ich finde keine Garantie dafür. Für einen schnellen Test würde ich vermutlich ähnlich vorgehen aber ich hätte so meine Zweifel.
 
Nur fehlt mir irgendwie die Garantie, dass der zurückgelieferte negative Index richtig ist. Ich habe mir noch mal die Api von String, binarySearch usw. angeschaut. Ich finde keine Garantie dafür.

https://docs.oracle.com/en/java/javase/21/docs/api/java.base/java/util/Arrays.html#binarySearch(java.lang.Object[] hat gesagt.:
Returns: index of the search key, if it is contained in the array; otherwise, (-(insertion point) - 1). The insertion point is defined as the point at which the key would be inserted into the array: the index of the first element greater than the key, or a.length if all elements in the array are less than the specified key. Note that this guarantees that the return value will be >= 0 if and only if the key is found.
 
Wenn du eine Präfixsuche effizient implementieren willst für eine große Anzahl an möglichen zu durchsuchenden Strings, dann würde man das eh nicht linear als Liste implementieren, sondern als Trie bzw. Präfix-Tree bzw. Patricia-Trie bzw. Radix-Tree.
Siehe: https://en.wikipedia.org/wiki/Radix_tree
Hey, ich hätte kurz eine Frage dazu und habe nicht alle gelesen Links.

Würde es nicht genügen schon, wenn man vom gebuchten Präfix wiederholt das letzte Zeichen entfernen würde, bis der Präfix gefunden wurde?

Nach eine Überschlagsrechnung ich komme da auf ~ m x n x log n. Vielleicht könnte das jemand bestätige?
 
Gerne, nun schreibe ich auch nicht mehr von Smratphone. Angenommen, prefix sei gesucht. Wir entfernen nu so lange jeweils das letzte Zeichen von prefix, bis dieses im Baum gefunden wurde. Würde eine Suche im Baum n*log(n) kosten, käme ich da auf nicht mehr als m*n*log(n) Gesamtkosten, so m die Länge des prefixs wär. Das kann natürlich auch Nonsense sein - deshalb meine Frage an den @httpdigest oder an jemanden, der das wüsste.
 
Etwa so ... nur halt mit einer Baum-ähnlichen Struktur:

Java:
import java.util.Arrays;

public class Suche {

    public static Object[] suche(String[] arr, String prefix, int minLen) {
        String orgPrefix = prefix;
        while (true) {
            int index = Arrays.binarySearch(arr, prefix);
            if (index < 0) {
                if (prefix.isEmpty() || prefix.length() <= minLen) {
                    return new Object[]{false, orgPrefix, -Arrays.binarySearch(arr, orgPrefix) - 1};
                }
                prefix = prefix.substring(0, prefix.length() - 1);
            } else {
                return new Object[]{true, prefix, index};
            }
        }
    }

    public static void main(String[] args) {
        System.out.println(Arrays.toString(suche(new String[]{"a", "aa", "aaaa"}, "aaa", 0)));
        System.out.println(Arrays.toString(suche(new String[]{"a", "aa", "aaaa"}, "baaa", 0)));
        System.out.println(Arrays.toString(suche(new String[]{"a", "aa", "aaaa"}, "aaaa", 0)));
        System.out.println(Arrays.toString(suche(new String[]{"a", "aa", "aaaa"}, "", 0)));
        System.out.println(Arrays.toString(suche(new String[]{"a", "aa", "aaaa"}, "aaa", 3)));
    }

}
 
Würde eine Suche im Baum n*log(n) kosten
Dann solltest Du den Baum in die Tonne treten.

Aber ja: würde man das annehmen, dann würde Deine Präfixsuche in der Komplexitätsklasse O(mn log n) liegen.

Allerdings besteht die Aufgabe darin, nach einem Präfix, nicht aber nach einem beliebigen Präfix des gegebenen Präfix zu suchen.

Wenn ich nach Times suche, möchte ich nicht Trebuchet erhalten.

Nachtrag: auf dein Codebeispiel bezogen: wenn ich nach "Times New" suche, möchte ich nicht "Times" erhalten.
 
Zuletzt bearbeitet:
Hallo Forum
Vielen Dank an alle Beteiligten...

aber dieser Thread übersteigt so langsam meine Kompetenzen.. 😳
Ich möchte diesen als geschlossen betrachten.
Richi
 

Neue Themen


Zurück
Oben