문제

목록이 있고 이를 단일 값으로 줄이고 싶습니다(함수 프로그래밍 용어 "fold", Ruby 용어 inject), 좋다

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

나는 함수형 프로그래밍 아이디어(Scala)에 감염되었기 때문에 코드를 작성하는 것보다 더 쉽고 짧은 방법을 찾고 있습니다.

sb = new StringBuilder
for ... {
  append ...
}
sb.toString
도움이 되었습니까?

해결책

당신이 찾고있는 것은 문자열입니다 join() Java 8.0부터 사용된 메서드입니다.아래 방법 중 하나를 시도해 보세요.

  1. 정적 방법 String#join(delimiter, elements):

    Collection<String> source = Arrays.asList("a", "b", "c");
    String result = String.join(",", source);
    
  2. 개울 인터페이스는 Scala와 매우 유사한 접기 작업을 지원합니다. foldLeft 기능.다음 연결을 살펴보세요. 수집기:

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

    정적으로 가져올 수도 있습니다. Collectors.joining 코드를 더 명확하게 만듭니다.

    그런데 이 컬렉터는 특정 객체의 컬렉션에 적용될 수 있습니다:

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

다른 팁

원래 질문에 답하려면:

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; }

F는 다음과 같습니다.

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

DFA가 제안한 대로, 기능적 자바 이 기능 등을 구현했습니다.

예시 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(",")));

예 2:

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

예시 3:

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

주어진

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();
}

그러면 사용법은 다음과 같습니다.

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(); }
}
);

언어를 바꾸지 않고 일반 Java에 일부 기능적 측면을 적용하려는 경우 비록 당신은 할 수 있지만 람다J, 포크 조인(166y) 그리고 Google 컬렉션 해당 구문 설탕을 추가하는 데 도움이 되는 라이브러리입니다.

의 도움으로 Google 컬렉션 당신은 사용할 수 있습니다 조이너 수업:

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

Joiner.on(",") 불변 객체이므로 자유롭게 공유할 수 있습니다(예: 상수로).

다음과 같이 null 처리를 구성할 수도 있습니다. Joiner.on(", ").useForNull("nil"); 또는 Joiner.on(", ").skipNulls().

큰 문자열을 생성하는 동안 큰 문자열을 할당하지 않으려면 이를 사용하여 기존 Streams, StringBuilders 등에 추가할 수 있습니다.통해 Appendable 인터페이스 또는 StringBuilder 수업:

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

맵을 작성할 때 항목과 키+값 사이의 구분을 위해 두 가지 서로 다른 구분 기호가 필요합니다.

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

당신이 찾고 있는 것은 불행히도 Java에는 없는 문자열 "join" 기능입니다.너무 어렵지 않아야 하는 자신만의 조인 기능을 굴려야 합니다.

편집하다: org.apache.commons.lang.StringUtils 유용한 문자열 함수(조인 포함)가 많이 있는 것 같습니다.

불행히도 Java에서는 해당 루프를 벗어날 수 없습니다. 그러나 여러 라이브러리가 있습니다.예:여러 라이브러리를 사용해 볼 수 있습니다.

먼저 일반 펑터와 접기와 같은 기능적 프로젝션을 제공하는 Java용 기능 ​​라이브러리가 필요합니다.나는 강력하면서도 단순한 라이브러리를 다음과 같이 설계하고 구현했습니다. http://www.codeproject.com/KB/java/FunctionalJava.aspx (나는 언급된 다른 라이브러리가 지나치게 복잡하다는 것을 알았습니다).

그러면 솔루션은 다음과 같습니다.

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"

접기를 적용함으로써 실제로 고려해야 할 유일한 부분은 누산기와 요소를 받아들이고 누산기를 반환하는 연산자를 정의하는 세 줄의 코드인 Func2.call에 대한 구현입니다(제 구현에서는 빈 문자열과 null인 경우 해당 대소문자를 제거하면 코드가 2줄로 줄어듭니다.

Seq.foldl의 실제 구현은 다음과 같습니다. Seq는 Iterable<E>를 구현합니다.

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 컬렉션 injectInto(Ruby와 같은), makeString 및 AppendString이 있습니다.다음은 귀하의 예에서 작동합니다.

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);

메모:저는 GS 컬렉션의 개발자입니다.

불행하게도 Java는 함수형 프로그래밍 언어가 아니며 원하는 작업을 수행할 수 있는 좋은 방법이 없습니다.

나는 Apache Commons lib에 다음이 있다고 생각합니다. Join이라는 함수 그래도 당신이 원하는 것을 할 것입니다.

메소드에서 루프를 숨길 만큼 충분해야 합니다.

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();
}

재귀적으로 할 수 있을 것 같습니다.

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);
}

이제 다음을 사용할 수 있습니다. String.join() 자바 8로.

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

람다의 지원을 통해 다음 코드로 수행할 수 있습니다.

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()));                  
    }

다음은 뒤에 남겨진 노드의 정보를 유지하고 앞으로 나아갈 때 접어서 목록을 접는 코드입니다.

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 스타일(기능적):

// 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

그러한 함수는 없지만 다음과 같은 것을 만들어 필요할 때마다 호출할 수 있습니다.

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();

    }
}
라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top