Frage

Ich habe eine Liste und will es auf einen einzelnen Wert (funktionale Programmierung Begriff „fold“ Ruby Begriff inject) zu reduzieren, wie

Arrays.asList("a", "b", "c") ... fold ... "a,b,c"

Als ich infiziere bin mit dem funktionalen Programmierung Ideen (Scala), ich bin auf der Suche nach einem einfacheren / kürzeren Weg, es zu codieren als

sb = new StringBuilder
for ... {
  append ...
}
sb.toString
War es hilfreich?

Lösung

Was Sie suchen ist ein String join() Methode, die Java seit 8.0 hat. Versuchen Sie eine der folgenden Methoden.

  1. Statische Methode String#join(delimiter, elements) :

    Collection<String> source = Arrays.asList("a", "b", "c");
    String result = String.join(",", source);
    
  2. Streamen Schnittstelle unterstützt eine Falte Betrieb sehr ähnlich Scala foldLeft Funktion. Werfen Sie einen Blick auf die folgenden verketten Collector :

    Collection<String> source = Arrays.asList("a", "b", "c");
    String result = source.stream().collect(Collectors.joining(","));
    

    Sie möchten vielleicht statisch Collectors.joining importieren Ihren Code klarer machen.

    Übrigens kann dieser Kollektor mit einer Sammlung von irgendwelchen besonderen Objekte angewendet werden:

    Collection<Integer> numbers = Arrays.asList(1, 2, 3);
    String result = numbers.stream()
            .map(Object::toString)
            .collect(Collectors.joining(","));
    

Andere Tipps

Ihre ursprüngliche Frage zu beantworten:

public static <A, B> A fold(F<A, F<B, A>> f, A z, Iterable<B> xs)
{ A p = z;
  for (B x : xs)
    p = f.f(p).f(x);
  return p; }

Wo F sieht wie folgt aus:

public interface F<A, B> { public B f(A a); }

Wie DFA vorgeschlagen, Functional Java diese umgesetzt hat und mehr.

Beispiel 1:

import fj.F;
import static fj.data.List.list;
import static fj.pre.Monoid.stringMonoid;
import static fj.Function.flip;
import static fj.Function.compose;

F<String, F<String, String>> sum = stringMonoid.sum();
String abc = list("a", "b", "c").foldLeft1(compose(sum, flip(sum).f(",")));

Beispiel 2:

import static fj.data.List.list;
import static fj.pre.Monoid.stringMonoid;
...
String abc = stringMonoid.join(list("a", "b", "c"), ",");

Beispiel 3:

import static fj.data.Stream.fromString;
import static fj.data.Stream.asString;
...
String abc = asString(fromString("abc").intersperse(','));

Da

public static <T,Y> Y fold(Collection<? extends T> list, Injector<T,Y> filter){
  for (T item : list){
    filter.accept(item);
  }
  return filter.getResult();
}

public interface Injector<T,Y>{
  public void accept(T item);
  public Y getResult();
}

Dann Nutzung sieht genauso aus wie

fold(myArray, new Injector<String,String>(){
  private StringBuilder sb = new StringBuilder();
  public void Accept(String item){ sb.append(item); }
  public String getResult() { return sb.toString(); }
}
);

Wenn Sie einige funktionale Aspekte zu Plain Old Java anwenden möchten, ohne Sprachumschaltung obwohl man konnte LamdaJ , fork-join (166Y) und google-Sammlungen Bibliotheken, die Sie, dass syntaktischen Zucker hinzufügen können.

Mit Hilfe von google-Sammlungen können Sie die Joiner Klasse :

Joiner.on(",").join("a", "b", "c")

Joiner.on(",") ist ein unveränderliches Objekt, so dass Sie es frei teilen können (zum Beispiel als eine Konstante).

Sie können auch null Handhabung wie Joiner.on(", ").useForNull("nil"); oder Joiner.on(", ").skipNulls() konfigurieren.

big Strings Zuweisung Um zu vermeiden, während Sie eine große Zeichenfolge generieren, können Sie es verwenden, um vorhandene Bäche, Stringbuilders usw. durch die Appendable Schnittstelle oder StringBuilder Klasse anhängen:

Joiner.on(",").appendTo(someOutputStream, "a", "b", "c");

Wenn Karten auszuschreiben, müssen Sie zwei verschiedene Separatoren für Einträge und Trennung zwischen Taste + Wert:

Joiner.on(", ").withKeyValueSeparator(":")
            .join(ImmutableMap.of(
            "today", "monday"
            , "tomorrow", "tuesday"))

Was Sie suchen ist eine Zeichenfolge „Join“ Funktion, die leider Java nicht haben. Sie müssen Ihre eigene Join-Funktion rollen, die nicht zu schwer sein sollte.

Edit: org.apache.commons.lang.StringUtils scheint viele nützliche String-Funktionen (einschließlich beitreten).

leider in Java Sie nicht, dass die Schleife entkommen können, gibt es mehrere Bibliotheken jedoch. Z.B. Sie können mehrere Bibliotheken versuchen:

Zunächst müssen Sie eine Funktionsbibliothek für Java, die generische functors und funktionale Projektionen wie Falte liefert. Ich habe entworfen und implementiert eine leistungsstarke (kraft) dennoch einfach solche Bibliothek hier: http: //www.codeproject.com/KB/java/FunctionalJava.aspx (fand ich die anderen Bibliotheken zu kompliziert erwähnt).

Dann ist Ihre Lösung würde wie folgt aussehen:

Seq.of("","a",null,"b","",null,"c","").foldl(
    new StringBuilder(), //seed accumulator
    new Func2<StringBuilder,String,StringBuilder>(){
        public StringBuilder call(StringBuilder acc,String elmt) {
            if(acc.length() == 0) return acc.append(elmt); //do not prepend "," to beginning
            else if(elmt == null || elmt.equals("")) return acc; //skip empty elements
            else return acc.append(",").append(elmt);
        }
    }
).toString(); //"a,b,c"

Beachten Sie, dass Falte durch die Anwendung, der einzige Teil, der Implementierung werden muss wirklich durchdacht für Func2.call ist, 3 Zeilen Code, die ein Bediener die Annahme des Akkumulators und ein Element und Rückführen des Akkumulators (meine Implementierung Konten für leere Strings und Nullen, wenn Sie diesen Fall entfernen dann ist es um 2 Zeilen Code).

Und hier ist die tatsächliche Umsetzung von Seq.foldl, Seq implementiert Iterable :

public <R> R foldl(R seed, final Func2<? super R,? super E,? extends R> binop)
{
    if(binop == null)
        throw new NullPointerException("binop is null");

    if(this == EMPTY)
        return seed;

    for(E item : this)
        seed = binop.call(seed, item);

    return seed;
}

GS Kollektionen injectInto hat (wie Ruby), Mache-und appendString. Im Folgenden wird mit Ihrem Beispiel arbeiten:

String result1 = FastList.newListWith("a", "b", "c").makeString(",");
StringBuilder sb = new StringBuilder();
FastList.newListWith("a", "b", "c").appendString(sb, ",");
String result2 = sb.toString();
Assert.assertEquals("a,b,c", result1); 
Assert.assertEquals(result1, result2);

. Hinweis: Ich bin ein Entwickler auf GS Sammlungen

Leider Java ist keine funktionale Sprache Programmierung und hat keine gute Art und Weise zu tun, was Sie wollen.

Ich glaube, die Apache Commons lib hat eine Funktion beitreten aufgerufen, was Sie aber wollen tun wird.

Es muss gut genug sein, um die Schleife in einem Verfahren zu verbergen.

public static String combine(List<String> list, String separator){
    StringBuilder ret = new StringBuilder();
    for(int i = 0; i < list.size(); i++){
        ret.append(list.get(i));
        if(i != list.size() - 1)
            ret.append(separator);
    }
    return ret.toString();
}

Ich nehme an, Sie könnte es tun rekursiv:

public static String combine(List<String> list, String separator){
    return recursiveCombine("", list, 0, separator);
}

public static String recursiveCombine(String firstPart, List<String> list, int posInList, String separator){
    if (posInList == list.size() - 1) return firstPart + list.get(posInList);

    return recursiveCombine(firstPart + list.get(posInList) + separator, list, posInList + 1, seperator);
}

Jetzt können Sie String.join() mit Java 8 verwenden.

    List strings = Arrays.asList("a", "b", "c");
    String joined = String.join(",", strings);
    System.out.println(joined);

Mit der Unterstützung von lambdas wir mit dem folgenden Code tun könnten:

static <T, R> R foldL(BiFunction<R, T, R> lambda, R zero, List<T> theList){

     if(theList.size() == 0){
      return zero;
     }

     R nextZero = lambda.apply(zero,theList.get(0));

     return foldL(lambda, nextZero, theList.subList(1, theList.size()));                  
    }

Im Folgenden finden Sie den Code um die Liste zu falten, indem sie die Informationen der Knoten zurückzuhalten lassen hinter und Falten wie wir vorankommen.

public class FoldList {
    public static void main(String[] args) {
        Node a = new Node(1);
        Node b = new Node(2);
        Node c = new Node(3);
        Node d = new Node(4);
        Node e = new Node(5);
        Node f = new Node(6);
        Node g = new Node(7);
        Node h = new Node(8);
        Node i = new Node(9);
        a.next = b;
        b.next = c;
        c.next = d;
        d.next = e;
        e.next = f;
        f.next = g;
        g.next = h;
        h.next = i;

        foldLinkedList(a);

    }

    private static void foldLinkedList(Node a) {
        Node middle = getMiddleNodeOfTheList(a);
        reverseListOnWards(middle);
        foldTheList(a, middle);

    }

    private static Node foldTheList(Node a, Node middle) {
        Node leftBackTracePtr = a;
        Node leftForwardptr = null;
        Node rightBackTrack = middle;
        Node rightForwardptr = null;
        Node leftCurrent = a;
        Node rightCurrent = middle.next;
        while (middle.next != null) {
            leftForwardptr = leftCurrent.next;
            rightForwardptr = rightCurrent.next;
            leftBackTracePtr.next = rightCurrent;
            rightCurrent.next = leftForwardptr;
            rightBackTrack.next = rightForwardptr;
            leftCurrent = leftForwardptr;
            leftBackTracePtr = leftCurrent;
            rightCurrent = middle.next;
        }
        leftForwardptr = leftForwardptr.next;
        leftBackTracePtr.next = middle;
        middle.next = leftForwardptr;

        return a;

    }

    private static void reverseListOnWards(Node node) {
        Node startNode = node.next;
        Node current = node.next;
        node.next = null;
        Node previous = null;
        Node next = node;
        while (current != null) {
            next = current.next;
            current.next = previous;
            previous = current;
            current = next;
        }
        node.next = previous;

    }

    static Node getMiddleNodeOfTheList(Node a) {
        Node slowptr = a;
        Node fastPtr = a;
        while (fastPtr != null) {
            slowptr = slowptr.next;
            fastPtr = fastPtr.next;
            if (fastPtr != null) {
                fastPtr = fastPtr.next;
            }
        }
        return slowptr;

    }

    static class Node {
        public Node next;
        public int value;

        public Node(int value) {
            this.value = value;
        }

    }
}

Java 8 Stil (funktionale):

// Given
List<String> arr = Arrays.asList("a", "b", "c");
String first = arr.get(0);

arr = arr.subList(1, arr.size());
String folded = arr.stream()
            .reduce(first, (a, b) -> a + "," + b);

System.out.println(folded); //a,b,c

Es gibt keine solche Funktion, aber Sie so etwas wie die folgenden erstellen können, und es aufrufen, wenn Sie benötigen.

import java.util.Arrays;
import java.util.List;

public class FoldTest {
    public static void main( String [] args ) {
        List<String> list = Arrays.asList("a","b","c");
        String s = fold( list, ",");
        System.out.println( s );
    }
    private static String fold( List<String> l, String with  ) {
        StringBuilder sb = new StringBuilder();
        for( String s: l ) {
            sb.append( s ); 
            sb.append( with );
        }
        return sb.deleteCharAt(sb.length() -1 ).toString();

    }
}
Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top