[JAVA] So verwenden Sie ein Array für den TreeMap-Schlüssel

In So verwenden Sie ein Array für den Schlüssel von HashMap sollte es anders sein, wenn es TreeMap ist, aber ich konnte es nicht sofort überprüfen, also habe ich es geteilt.

TreeMap-Schlüsselannahmen

Hier heißt es TreeMap. HashMap ist etwas anders. → Verwendung eines Arrays für HashMap-Schlüssel Die Hauptannahme ist --Implementieren gleich --Comparator wird an oder TreeMap übergeben, das Comparable implementiert

Das erste ist, dass das enthältKey, get und put von TreeSet compareTo verwendet. Genau genommen ist dies möglicherweise nicht erforderlich, aber es ist erforderlich. Das zweite ist, dass die Implementierung von Compareable die Implementierung von compareTo bedeutet. Wenn es nicht vergleichbar gemacht werden kann, bereiten Sie einen separaten Komparator vor und übergeben Sie ihn an den TreeMap-Konstruktor. Der dritte ist nicht unveränderlich und kann später geändert werden. Wenn Sie jedoch den Schlüsselwert nach dem Einfügen ändern, wird er möglicherweise nicht gefunden. Dies ist in einem gegabelten Baum implementiert. Wenn Sie also den Schlüssel von außen ändern und rechts oder links falsch sind, explodiert er.

Der Unterschied zwischen HashMap und TreeMap besteht darin, ob Sie hashCode oder compareTo benötigen. Wenn Sie beide haben, können Sie sowohl HashMap als auch TreeMap verwenden.

Ergebnisse von Array gleich und HashCode

Wenn es sich um ein Array handelt, ist equals nicht korrekt und implementiert Comparable nicht.

Main.java


    public static void main(String[] args) {
        byte[] b01 = { 1, 2, 3 };
        byte[] b02 = { 1, 2, 3 };
        System.out.println(b01 == b02);
        System.out.println(b01.equals(b02));
        System.out.println(Arrays.equals(b01, b02));
        //Comparable c = (Comparable)b01;
        TreeMap<byte[], String> map = new TreeMap<>();
        map.put(b01, "OK");
    }

Auskommentierte Casts führen zu einem Kompilierungsfehler. Wenn du rennst ...

false
false
true
Exception in thread "main"
java.lang.ClassCastException: [B cannot be cast to java.lang.Comparable
    at java.util.TreeMap.compare(TreeMap.java:1290)
    at java.util.TreeMap.put(TreeMap.java:538)
    at Main.main(Main.java:15)

Ich habe Arrays.equals, aber ich muss mich selbst vergleichen.

Teil 1: Verwenden Sie ByteBuffer

Ich habe mich gefragt, wer Comparable überhaupt implementiert hat, und als ich grep habe, habe ich auch das java.nio.Buffer-Corps implementiert.

Lass es uns testen.

Main.java


    public static void main(String[] args) {
        byte[] b01 = { 1, 2, 3 };
        byte[] b02 = { 1, 2, 3 };
        ByteBuffer w01 = ByteBuffer.wrap(b01);
        ByteBuffer w02 = ByteBuffer.wrap(b02);
        Map<ByteBuffer, String> map = new TreeMap<>();
        map.put(w01, "OK");
        System.out.println(w01 == w02);
        System.out.println(w01.equals(w02));
        System.out.println(map.get(w01));
        System.out.println(map.get(w02));
    }

Wenn du rennst ...

false
true
OK
OK

OK überhaupt. Das ist das beste Gefühl. Ich mag die Standardbibliothek, die aus JDK 1.4 hinzugefügt wurde.

Teil 2: Erstellen Sie einen ByteArrayWrapper

Ich wage es, eine Klasse zu erstellen, die Byte [] umschließt. Ich habe ByteBuffer als Referenz verwendet.

ByteArrayWrapper.java


import java.util.Arrays;

public class ByteArrayWrapper implements Comparable<ByteArrayWrapper> {
    private byte[] data;

    public ByteArrayWrapper(byte[] data) {
        this.data = data.clone();
    }

    public boolean equals(Object other) {
        if (other instanceof ByteArrayWrapper) {
            return Arrays.equals(data, ((ByteArrayWrapper) other).data);
        }
        return false;
    }

    public int compareTo(ByteArrayWrapper that) {
        int n = Math.min(this.data.length, that.data.length);
        for (int i = 0; i < n; i++) {
            int cmp = Byte.compare(this.data[i], that.data[i]);
            if (cmp != 0)
                return cmp;
        }
        return this.data.length - that.data.length;
    }
}

Lass es uns testen.

Main.java


    public static void main(String[] args) {
        byte[] b01 = { 1, 2, 3 };
        byte[] b02 = { 1, 2, 3 };
        ByteArrayWrapper w01 = new ByteArrayWrapper(b01);
        ByteArrayWrapper w02 = new ByteArrayWrapper(b02);
        Map<ByteArrayWrapper, String> map = new TreeMap<>();
        map.put(w01, "OK");
        System.out.println(w01 == w02);
        System.out.println(w01.equals(w02));
        System.out.println(map.get(w01));
        System.out.println(map.get(w02));
    }

Ergebnis ist ···

false
true
OK
OK

Ich klone () dieses Mal basierend auf der Lektion, die ich von HashMap gelernt habe, aber es ist wahrscheinlich in Ordnung.

Modifizierter ByteArray Wrapper

(1/18 postscript) Ich habe versucht, das Problem zu beheben, indem ich das Argument des Konstruktors im Kommentar von byte [] in byte ... (Argument variabler Länge) geändert habe.

ByteArrayWrapper.java


import java.util.Arrays;

public class ByteArrayWrapper implements Comparable<ByteArrayWrapper> {
    private byte[] data;

    public ByteArrayWrapper(byte... data) {
        this.data = data.clone();
    }

    public boolean equals(Object other) {
        if (other instanceof ByteArrayWrapper) {
            return Arrays.equals(data, ((ByteArrayWrapper) other).data);
        }
        return false;
    }
    
    public int compareTo(ByteArrayWrapper that) {
        int n = Math.min(this.data.length, that.data.length);
        for (int i = 0; i < n; i++) {
            int cmp = Byte.compare(this.data[i], that.data[i]);
            if (cmp != 0)
                return cmp;
        }
        return this.data.length - that.data.length;
    }
}

Sie können das Array wie zuvor oder als ByteArrayWrapper (1, 2, 3) übergeben. Es sollte sein, aber es gab nicht viel Verdienst im Bytetyp, weil es Casting erforderte. Mit int type und long type können Sie eine Instanz ohne Casting und ohne Vorbereitung eines Arrays erstellen.

Main.java


    public static void main(String[] args) {
        byte[] b01 = { 1, 2, 3 };
        ByteArrayWrapper w01 = new ByteArrayWrapper(b01);
        ByteArrayWrapper w02 = new ByteArrayWrapper((byte)1, (byte)2, (byte)3);
        Map<ByteArrayWrapper, String> map1 = new HashMap<>();
        map1.put(w01, "OK");
        Map<ByteArrayWrapper, String> map2 = new TreeMap<>();
        map2.put(w01, "OK");
        System.out.println(map1.get(w01));
        System.out.println(map1.get(w02));
        System.out.println(map2.get(w01));
        System.out.println(map2.get(w02));
    }

Teil 3: Verwenden Sie BigInteger → Nr

java.math.BigInteger ist ebenfalls vergleichbar, kann jedoch nicht verwendet werden, da aus {0, 100} {100} wird.

Teil 4: In eine Zeichenfolge konvertieren → Nicht effizient

Es wäre schön, wenn HashMap eindeutig wäre, aber TreeMap hat eine Größenbeziehung, sodass es keine andere Wahl gibt, als den numerischen Wert auf eine feste Länge festzulegen. Wenn nicht genügend Ziffern vorhanden sind, geben Sie links 0 ein.

Teil 5: Übergeben Sie den Komparator an TreeMap

(1/18 Nachschrift) Am Anfang schrieb ich, dass "Comparable implementiert ist oder Comparer an TreeMap übergibt", und ich machte nur das Beispiel von Comparable, also machte ich zusätzlich ein Beispiel von Comparer.

Teil 1 bis Teil 3 ist eine Methode zum Implementieren und Realisieren von Comparable, die Byte [] umschließt. Der fünfte ist der Fall der Herstellung eines Komparators, der eine andere Methode darstellt.

Es ist fast dasselbe wie compareTo von ByteArrayWrapper, erstellt jedoch ByteArrayComparator.

ByteArrayComparator.java


import java.util.Comparator;

public class ByteArrayComparator implements Comparator<byte[]> {
    public int compare(byte[] o1, byte[] o2) {
        int n = Math.min(o1.length, o2.length);
        for (int i = 0; i < n; i++) {
            int cmp = Byte.compare(o1[i], o2[i]);
            if (cmp != 0)
                return cmp;
        }
        return o1.length - o2.length;
    }
}

Lass es uns testen.

Main.java


    public static void main(String[] args) {
        byte[] b01 = { 1, 2, 3 };
        byte[] b02 = { 1, 2, 3 };
        Map<byte[], String> map = new TreeMap<>(new ByteArrayComparator());
        map.put(b01, "OK");
        System.out.println(map.get(b01));
        System.out.println(map.get(b02));
    }

Ergebnis ist ···

OK
OK

Vielleicht ist es okay.

Schließlich

Es wurde bestätigt, dass ByteArrayWrapper keinen HashCode in TreeMap benötigt, aber normalerweise ist es besser, beide zu implementieren, wenn Sie es trotzdem machen. (1/18 postscript) Ich habe das Argument des Konstruktors von byte [] in byte ... geändert (Argument variabler Länge). Auch hinzugefügt gleich (Byte [] andere).

ByteArrayWrapper.java


import java.util.Arrays;

public class ByteArrayWrapper implements Comparable<ByteArrayWrapper> {
    private byte[] data;

    public ByteArrayWrapper(byte... data) {
        this.data = data.clone();
    }

    public boolean equals(Object other) {
        if (other instanceof ByteArrayWrapper) {
            return equals(((ByteArrayWrapper) other).data);
        }
        return false;
    }
    
    public boolean equals(byte[] other) {
        return Arrays.equals(data, other);
    }
    
    public int hashCode() {
        return Arrays.hashCode(data);
    }

    public int compareTo(ByteArrayWrapper that) {
        int n = Math.min(this.data.length, that.data.length);
        for (int i = 0; i < n; i++) {
            int cmp = Byte.compare(this.data[i], that.data[i]);
            if (cmp != 0)
                return cmp;
        }
        return this.data.length - that.data.length;
    }
}

Main.java


    public static void main(String[] args) {
        byte[] b01 = { 1, 2, 3 };
        ByteArrayWrapper w01 = new ByteArrayWrapper(b01);
        ByteArrayWrapper w02 = new ByteArrayWrapper((byte)1, (byte)2, (byte)3);
        Map<ByteArrayWrapper, String> map1 = new HashMap<>();
        map1.put(w01, "OK");
        Map<ByteArrayWrapper, String> map2 = new TreeMap<>();
        map2.put(w01, "OK");
        System.out.println(map1.get(w01));
        System.out.println(map1.get(w02));
        System.out.println(map2.get(w01));
        System.out.println(map2.get(w02));
    }

Wenn ich teste ...

OK
OK
OK
OK

Recommended Posts

So verwenden Sie ein Array für den TreeMap-Schlüssel
So verwenden Sie ein Array für HashMap-Schlüssel
So erstellen Sie Pagenationen für das "Kaminari" -Array
[Java] So drehen Sie ein zweidimensionales Array mit einer erweiterten for-Anweisung
So erstellen Sie eine Beurteilungsmethode, um nach einem beliebigen Zeichen im Array zu suchen
So erstellen Sie ein Java-Array
So ändern Sie eine Zeichenfolge in einem Array in eine Zahl in Ruby
So geben Sie Array-Werte ohne Verwendung einer for-Anweisung aus
Verwendung von binding.pry für die Ansichtsdatei
So fügen Sie einen neuen Hash / Array hinzu
So erstellen Sie ein Maven-Repository für 2020
[Ruby] Wie man Slice für Anfänger benutzt
[Java] So suchen Sie mit der Methode includes nach Werten in einem Array (oder einer Liste)
[Für Rails-Anfänger] Zusammenfassung der Verwendung von RSpec (Überblick)
[Java] [Für Anfänger] So fügen Sie Elemente direkt in ein zweidimensionales Array ein
So erstellen Sie überall eine H2-Datenbank
So erstellen Sie eine leichte JRE für den Vertrieb
So generieren Sie einen Primärschlüssel mit @GeneratedValue
[Für Super-Anfänger] Verwendung des Autofokus: true
Verwendung von Map
Wie benutzt man rbenv?
Verwendung mit_option
Verwendung von fields_for
Verwendung von java.util.logging
Verwendung der Karte
Verwendung von collection_select
Wie benutzt man Twitter4J
Wie benutzt man active_hash! !!
Verwendung von MapStruct
Verwendung von TreeSet
[Verwendung des Etiketts]
Wie man Identität benutzt
Wie man Hash benutzt
Verwendung von Dozer.mapper
Wie benutzt man Gradle?
Verwendung von org.immutables
Verwendung von java.util.stream.Collector
Verwendung von VisualVM
Verwendung von Map
[Java] So konvertieren Sie ein Element eines Array vom Typ String in einen Int-Typ
So schreiben Sie einen Komponententest für Spring Boot 2
Wie schreibe ich, um Edelstein Pagy (Pagenation) auf ein Array anzuwenden
[Spring Boot] So erstellen Sie ein Projekt (für Anfänger)
So geben Sie einen Standard aus einem Array mit for Each aus
Verwendung von Truth (Assertion Library für Java / Android)
[Für diejenigen, die Portfolios erstellen] Verwendung von Font-Awesome-Rails
So konvertieren Sie eine Datei in ein Byte-Array in Java
Wie erstelle ich einen MOD für Slay the Spire?
Wie man GitHub für Super-Anfänger benutzt (Teamentwicklung)
[Java] Verwendung von Map