목록을 쉼표로 구분하는 가장 간단한 방법은 무엇입니까?


104

Java에서 목록을 쉼표로 구분하는 가장 명확한 방법은 무엇입니까?

여러 가지 방법을 알고 있지만 가장 좋은 방법이 무엇인지 궁금합니다 ( "최고"는 가장 효율적이지 않고 가장 명확하고 짧은 것을 의미합니다.

나는 목록이 있고 그것을 반복하여 각 값을 인쇄하고 싶습니다. 각 항목 사이에 쉼표를 인쇄하고 싶지만 마지막 항목 뒤 (또는 첫 번째 항목 앞)가 아닙니다.

List --> Item ( , Item ) *
List --> ( Item , ) * Item

샘플 솔루션 1 :

boolean isFirst = true;
for (Item i : list) {
  if (isFirst) {
    System.out.print(i);        // no comma
    isFirst = false;
  } else {
    System.out.print(", "+i);   // comma
  }
}

샘플 솔루션 2-하위 목록 만들기 :

if (list.size()>0) {
  System.out.print(list.get(0));   // no comma
  List theRest = list.subList(1, list.size());
  for (Item i : theRest) {
    System.out.print(", "+i);   // comma
  }
}

샘플 솔루션 3 :

  Iterator<Item> i = list.iterator();
  if (i.hasNext()) {
    System.out.print(i.next());
    while (i.hasNext())
      System.out.print(", "+i.next());
  }

이들은 첫 번째 항목을 특별히 취급합니다. 대신 마지막 하나를 특별히 다룰 수 있습니다.

덧붙여, 여기에 어떻게 List toString 되어 (이 상속 것 구현 AbstractCollection자바 1.6) :

public String toString() {
    Iterator<E> i = iterator();
    if (! i.hasNext())
        return "[]";

    StringBuilder sb = new StringBuilder();
    sb.append('[');
    for (;;) {
        E e = i.next();
        sb.append(e == this ? "(this Collection)" : e);
        if (! i.hasNext())
            return sb.append(']').toString();
        sb.append(", ");
    }
}

마지막 항목 뒤의 쉼표를 피하기 위해 루프를 일찍 종료합니다. BTW : "(이 컬렉션)"을 본 것은 이번이 처음입니다. 그것을 유발하는 코드는 다음과 같습니다.

List l = new LinkedList();
l.add(l);
System.out.println(l);

예기치 않은 라이브러리 (regexp?)를 사용하더라도 모든 솔루션을 환영합니다. 자바 이외의 언어로도 솔루션 (예를 들어 파이썬 / 루비가 생각 산재 기능 - 방법 있음 ? 구현을).

설명 : 라이브러리 란 표준 Java 라이브러리를 의미합니다. 다른 라이브러리의 경우 다른 언어로 고려하고 구현 방법을 알고 싶습니다.

EDIT 툴킷이 비슷한 질문을 언급했습니다. 자바에서 향상된 for 루프의 마지막 반복

그리고 또 다른 : 루프의 마지막 요소는 별도의 처리가 필요합니까?


답변:


226

Java 8 이상

StringJoiner수업 사용 :

StringJoiner joiner = new StringJoiner(",");
for (Item item : list) {
    joiner.add(item.toString());
}
return joiner.toString();

Stream, 및 사용 Collectors:

return list.stream().
       map(Object::toString).
       collect(Collectors.joining(",")).toString();

Java 7 이하

참조 # 285523

String delim = "";
for (Item i : list) {
    sb.append(delim).append(i);
    delim = ",";
}

1
상태를 저장하는 매우 놀라운 방법! 거의 OO 다형성입니다. 모든 루프마다 불필요한 할당이 마음에 들지는 않지만 if보다 효율적입니다. 대부분의 솔루션은 사실이 아닐 것이라고 알고있는 테스트를 반복합니다. 비효율적이지만 아마도 가장 명확 할 것입니다. 링크 주셔서 감사합니다!
13ren

1
나는 이것을 좋아하지만 영리하고 놀랍기 때문에 사용하기에 적절하지 않을 것이라고 생각했습니다 (놀라운 것은 좋지 않습니다!). 그러나 나는 스스로를 도울 수 없었다. 나는 그것에 대해 아직 확실하지 않습니다. 그러나 너무 짧아서 팁을 줄 댓글이 있으면 쉽게 해결할 수 있습니다.
13ren

6
@ 13ren : 당신과 Bob 삼촌은 "영리하고 놀라운"코드에 대해 이야기해야합니다.
Stefan Kendall

이걸 모르고 세월을 낭비한 것 같아요 ^^;
Lake

Java가 이러한 작업을 추악한 코드로 바꿔야하는 이유는 무엇입니까?
Eduardo

82
org.apache.commons.lang3.StringUtils.join(list,",");

1
소스를 찾았습니다 : svn.apache.org/viewvc/commons/proper/lang/trunk/src/java/org/… join 메소드에는 9 개의 오버로딩이 있습니다. 반복 기반은 "샘플 솔루션 3"과 같습니다. 인덱스 기반 사용 : if (i> startIndex) {<add separator>}
13ren

나는 정말 구현 후입니다. 함수로 감싸는 것이 좋지만 실제로 내 구분 기호는 때때로 개행 문자이며 각 행은 지정된 깊이까지 들여 쓰기됩니다. join (list, "\ n"+ indent) ... 항상 작동하지 않는 한? 죄송합니다. 큰 소리로 생각하고 있습니다.
13ren

2
제 생각에는,이 예쁜 및 짧은 솔루션입니다
예스퍼 Rønn - 젠슨

아마도 list.iterator ()?
Vanuan 2013-08-30

32

Java 8은이를위한 몇 가지 새로운 방법을 제공합니다.

  • join방법 String.
  • 클래스의 joining스트림에 대한 수집기입니다 Collectors.
  • StringJoiner클래스입니다.

예:

// Util method for strings and other char sequences
List<String> strs = Arrays.asList("1", "2", "3");
String listStr1 = String.join(",", strs);

// For any type using streams and collectors
List<Object> objs = Arrays.asList(1, 2, 3);
String listStr2 = objs.stream()
    .map(Object::toString)
    .collect(joining(",", "[", "]"));

// Using the new StringJoiner class
StringJoiner joiner = new StringJoiner(", ", "[", "]");
joiner.setEmptyValue("<empty>");
for (Integer i : objs) {
  joiner.add(i.toString());
}
String listStr3 = joiner.toString();

스트림을 사용하는 접근 방식은 import static java.util.stream.Collectors.joining;.


이것은 IMHO입니다. Java 8을 사용하는 경우 가장 좋은 답변입니다.
scravy


7

Spring Framework를 사용한다면 StringUtils로 할 수 있습니다 .

public static String arrayToDelimitedString(Object[] arr)
public static String arrayToDelimitedString(Object[] arr, String delim)
public static String collectionToCommaDelimitedString(Collection coll)
public static String collectionToCommaDelimitedString(Collection coll, String delim)

감사합니다. 어떻게 구현됩니까?
13ren

6

Java의 List toString 구현을 기반으로 :

Iterator i = list.iterator();
for (;;) {
  sb.append(i.next());
  if (! i.hasNext()) break;
  ab.append(", ");
}

다음과 같은 문법을 사용합니다.

List --> (Item , )* Item

첫 번째 기반이 아닌 마지막 기반이기 때문에 목록 끝을 확인하기 위해 동일한 테스트로 쉼표 건너 뛰기를 확인할 수 있습니다. 나는 이것이 매우 우아하다고 생각하지만 명확성이 확실하지 않습니다.


4
String delimiter = ",";
StringBuilder sb = new StringBuilder();
for (Item i : list) {
    sb.append(delimiter).append(i);
}
sb.toString().replaceFirst(delimiter, "");


3
for(int i=0, length=list.size(); i<length; i++)
  result+=(i==0?"":", ") + list.get(i);

예, 약간 모호하지만 이미 게시 된 것에 대한 대안입니다.
cherouvim

1
나는 코드가 괜찮아 보인다고 생각한다. IMHO는 다른 대답보다 더 예쁘고 거의 '암호화'되지 않습니다. Join이라는 방법으로 마무리하고 웃으면서도 언어가 정말로 일반적인 문제를 해결하는 더 나은 방법을 기대합니다.
tarn

@tarn : 당신은 당신이 파이썬 / 펄 배경이 있기 때문에 잘 보이는 생각) 좋아 나뿐만 아니라
cherouvim

3

foreach 루프에 대한 한 가지 옵션은 다음과 같습니다.

StringBuilder sb = new StringBuilder();
for(String s:list){
  if (sb.length()>0) sb.append(",");
  sb.append(s);
}

2
StringBuffer result = new StringBuffer();
for(Iterator it=list.iterator; it.hasNext(); ) {
  if (result.length()>0)
    result.append(", ");
  result.append(it.next());
}

업데이트 : Dave Webb이 주석에서 언급했듯이 목록의 첫 번째 항목이 빈 문자열 인 경우 올바른 결과를 생성하지 못할 수 있습니다.


meh .. 여전히 루프에 if가 있습니다.
sfossen

foreach 루프를 사용하여 더 짧게 만들 수 있습니다.
Peter Lawrey

목록의 첫 번째 항목이 빈 문자열이면 작동하지 않습니다.
Dave Webb

@Dave Webb : 네, 감사합니다. 그러나 질문에는 그러한 요구 사항이 없습니다.
cherouvim

@cherovium : 질문은 항목 중 어느 것도 빈 문자열이 아니라는 것을 말하지 않으므로 암시 적 요구 사항입니다. CSV 파일을 만드는 경우 빈 필드가 매우 일반적 일 수 있습니다.
Dave Webb

2

나는 보통 이것을한다 :

StringBuffer sb = new StringBuffer();
Iterator it = myList.iterator();
if (it.hasNext()) { sb.append(it.next().toString()); }
while (it.hasNext()) { sb.append(",").append(it.next().toString()); }

나는 지금부터 Java 구현에 따라이 검사를 할 것이라고 생각하지만;)


그것은 샘플 3과 같은 논리이며, 불필요한 것이 없기 때문에 좋아합니다. 그러나 그것이 가장 명확한 지 모르겠습니다. BTW : 목록이 비어있을 때 두 번의 테스트를 피함으로써 if 안에 while을 넣는 것이 약간 더 효율적입니다. 그것은 또한 나에게 그것을 더 명확하게 만듭니다.
13ren


2

(JVM에서 실행되는) Groovy를 사용할 수있는 경우 :

def list = ['a', 'b', 'c', 'd']
println list.join(',')

감사합니다.하지만 구현에 관심이 있습니다. 이것은 어떻게 구현됩니까?
13ren 03.

2

( 여기 에서 내 답변의 붙여 넣기 복사 .) 여기에 설명 된 많은 솔루션, IMHO, 특히 외부 라이브러리에 의존하는 솔루션이 약간 이상합니다. 내가 항상 사용했던 쉼표로 구분 된 목록을 얻기위한 깔끔하고 명확한 관용구가 있습니다. 조건부 (?) 연산자를 사용합니다.

편집 : 원래 솔루션은 정확하지만 의견에 따르면 최적이 아닙니다. 두 번째 시도 :

int[] array = {1, 2, 3};
StringBuilder builder = new StringBuilder();
for (int i = 0 ;  i < array.length; i++)
       builder.append(i == 0 ? "" : ",").append(array[i]);

배열 및 StringBuilder 선언을 포함하여 4 줄의 코드로 구성됩니다.

2 차 편집 : 반복자를 다루는 경우 :

    List<Integer> list = Arrays.asList(1, 2, 3);
    StringBuilder builder = new StringBuilder();
    for (Iterator it = list.iterator(); it.hasNext();)
        builder.append(it.next()).append(it.hasNext() ? "," : "");

이것과 stackoverflow.com/questions/668952/… 위는 비슷합니다. 짧고 명확하지만 반복자 만있는 경우 먼저 변환해야합니다. 비효율적이지만이 접근 방식의 명확성을 위해 그만한 가치가 있습니까?
13ren

어, StringBuilder를 사용하여 임시 StringBuilder를 만드는 문자열 연결입니다. 무능한. 더 나은 (Java와 비슷하지만 더 나은 코드 실행)은 "if (i> 0) {builder.append ( ',');}"다음에 builder.append (array [i]);
Eddie

예, 바이트 코드를 보면 맞습니다. 그런 간단한 질문이 그렇게 복잡해질 수 있다는 것을 믿을 수 없습니다. 컴파일러가 여기서 최적화 할 수 있는지 궁금합니다.
Julien Chastang

두 번째로 더 나은 솔루션을 제공했습니다.
Julien Chastang

분할하는 것이 더 나을 수 있습니다 (사람들이 둘 중 하나에 투표 할 수 있도록).
13ren

1

저는 보통 버전 3과 비슷한 것을 사용합니다. c / c ++ / bash / ... 잘 작동합니다. : P


1

나는 그것을 컴파일하지 않았지만 ... 작동해야합니다 (또는 작동에 가깝습니다).

public static <T> String toString(final List<T> list, 
                                  final String delim)
{
    final StringBuilder builder;

    builder = new StringBuilder();

    for(final T item : list)
    {
        builder.append(item);
        builder.append(delim);
    }

    // kill the last delim
    builder.setLength(builder.length() - delim.length());

    return (builder.toString());
}

이 방식이 마음에 들어 다른 형식을 선호합니다. 그러나 한 가지 작은 수정 사항을 언급해야합니다. 목록이 비어 있으면 IndexOutOfBounds 예외가 발생합니다. 따라서 setLength 전에 확인하거나 Math.max (0, ...)
tb-

1

이것은 매우 짧고 명확하지만 내 감성에 오싹한 공포를줍니다. 특히 문자열 (문자가 아님) 인 경우 다른 구분 기호에 적응하는 것도 약간 어색합니다.

for (Item i : list)
  sb.append(',').append(i);
if (sb.charAt(0)==',') sb.deleteCharAt(0);

영감을 받음 : Java에서 향상된 for 루프의 마지막 반복


1
StringBuffer sb = new StringBuffer();

for (int i = 0; i < myList.size(); i++)
{ 
    if (i > 0) 
    {
        sb.append(", ");
    }

    sb.append(myList.get(i)); 
}

나는 이것이 매우 읽기 쉽고 이해하기 쉬운 동시에 정적 유틸리티 클래스에 삽입하기가 매우 쉽다는 것을 알았습니다. 또한 목록 자체, 루프 및 구분 기호 이외의 추가 변수 또는 상태가 필요하지 않습니다.
Joachim H. Skeie 2011 년

이 같은 것을 제공 할 것입니다Item1Item2, Item3, Item4,


1

얼마 전에 블로그에서 찾은이 접근 방식이 다소 마음에 듭니다. 불행히도 블로그 이름 / URL이 기억 나지 않습니다.

다음과 같은 유틸리티 / 도우미 클래스를 만들 수 있습니다.

private class Delimiter
{
    private final String delimiter;
    private boolean first = true;

    public Delimiter(String delimiter)
    {
        this.delimiter = delimiter;
    }

    @Override
    public String toString()
    {
        if (first) {
            first = false;
            return "";
        }

        return delimiter;
    }
}

도우미 클래스를 사용하는 것은 다음과 같이 간단합니다.

StringBuilder sb = new StringBuilder();
Delimiter delimiter = new Delimiter(", ");

for (String item : list) {
    sb.append(delimiter);
    sb.append(item);
}

참고 : "구분자"가 아니라 "구분자"여야합니다.
Michael Myers

1

구분 기호가 ","이므로 다음 중 하나를 사용할 수 있습니다.

public class StringDelim {

    public static void removeBrackets(String string) {
        System.out.println(string.substring(1, string.length() - 1));
    }

    public static void main(String... args) {
        // Array.toString() example
        String [] arr = {"Hi" , "My", "name", "is", "br3nt"};
        String string = Arrays.toString(arr);
        removeBrackets(string);

        // List#toString() example
        List<String> list = new ArrayList<String>();
        list.add("Hi");
        list.add("My");
        list.add("name");
        list.add("is");
        list.add("br3nt");
        string = list.toString();
        removeBrackets(string);

        // Map#values().toString() example
        Map<String, String> map = new LinkedHashMap<String, String>();
        map.put("1", "Hi");
        map.put("2", "My");
        map.put("3", "name");
        map.put("4", "is");
        map.put("5", "br3nt");
        System.out.println(map.values().toString());
        removeBrackets(string);

        // Enum#toString() example
        EnumSet<Days> set = EnumSet.allOf(Days.class);
        string = set.toString();
        removeBrackets(string);
    }

    public enum Days {
        MON("Monday"),
        TUE("Tuesday"),
        WED("Wednesday"),
        THU("Thursday"),
        FRI("Friday"),
        SAT("Saturday"),
        SUN("Sunday");

        private final String day;

        Days(String day) {this.day = day;}
        public String toString() {return this.day;}
    }
}

구분 기호가 다른 경우에는 작동하지 않습니다.


1

이 솔루션을 좋아합니다.

String delim = " - ", string = "";

for (String item : myCollection)
    string += delim + item;

string = string.substring(delim.length());

나는 그것이 StringBuilder도 사용할 수 있다고 가정합니다.


1

제 생각에 이것은 읽고 이해하기 가장 간단합니다.

StringBuilder sb = new StringBuilder();
for(String string : strings) {
    sb.append(string).append(',');
}
sb.setLength(sb.length() - 1);
String result = sb.toString();

0

파이썬에서는 쉽다

",". join (목록)

C #에는 String 클래스에 정적 메서드가 있습니다.

String.Join ( ",", yourlistofstrings)

죄송합니다. Java에 대해서는 잘 모르겠지만 다른 언어에 대해 물었을 때 필자가 생각했습니다. Java에서도 비슷한 것이있을 것이라고 확신합니다.


IIRC, 당신은 .Net 버전에서 후행을 얻습니다. :-(

1
방금 테스트했으며 .NET 또는 Python에서 후행 구분 기호 없음
tarn

1
감사! 소스를 찾았습니다. svn.python.org/view/python/branches/release22-branch/Objects/… "Catenate everything"을 검색하십시오. 마지막 항목에 대한 구분 기호를 생략합니다.
13ren

@ 13ren 잘 했어! 도움이 되나요? 나는 자물쇠를 가지고 있었고 왜 내가 요즘 C로 프로그램하지 않기로 결정했는지 빨리 기억했다. : P
tarn

@tarn, 예, 마지막 항목이 아닌 경우에만 comman을 추가하기 때문에 흥미로운 예입니다. if (i <seqlen-1) {<add separator>}
13ren

0

또한 무조건 구분자 문자열을 추가 할 수 있으며 루프 후에 끝에서 추가 구분자를 제거 할 수 있습니다. 그런 다음 처음에 "목록이 비어있는 경우이 문자열을 반환"하면 끝에서 확인을 피할 수 있습니다 (빈 목록에서 문자를 제거 할 수 없기 때문에).

그래서 질문은 정말로 :

"루프와 if를 감안할 때, 이들을 함께 사용하는 가장 명확한 방법은 무엇이라고 생각하십니까?"


0
public static String join (List<String> list, String separator) {
  String listToString = "";

  if (list == null || list.isEmpty()) {
   return listToString;
  }

  for (String element : list) {
   listToString += element + separator;
  }

  listToString = listToString.substring(0, separator.length());

  return listToString;
}

1
나는 당신이 말하는 의미 생각listToString.substring(0, listToString.length()-separator.length());
13ren

0
if (array.length>0)          // edited in response Joachim's comment
  sb.append(array[i]);
for (int i=1; i<array.length; i++)
  sb.append(",").append(array[i]);

기반 목록 (Java)을 쉼표로 구분하는 가장 명확한 방법을 합니까?

이 아이디어를 사용하여 : 루프의 마지막 요소는 별도의 처리가 필요합니까?


1
이 작업을 수행하려면 목록에 최소 1 개의 요소가 있다는 것을 알아야합니다. 그렇지 않으면 첫 번째 for 루프가 IndexOutOfBoundsException과 함께 충돌합니다.
Joachim H. Skeie 2011 년

@Joachim 감사합니다, 당신은 물론 맞습니다. 내가 썼던 얼마나 추한 해결책! 나는 변경할 수 있습니다 for (int i=0; i<1; i++)if (array.length>0).
13ren

0
public String toString(List<Item> items)
{
    StringBuilder sb = new StringBuilder("[");

    for (Item item : items)
    {
        sb.append(item).append(", ");
    }

    if (sb.length() >= 2)
    {
        //looks cleaner in C# sb.Length -= 2;
        sb.setLength(sb.length() - 2);
    }

    sb.append("]");

    return sb.toString();
}


0

지금까지 어떤 답변도 재귀를 사용하지 않습니다 ...

public class Main {

    public static String toString(List<String> list, char d) {
        int n = list.size();
        if(n==0) return "";
        return n > 1 ? Main.toString(list.subList(0, n - 1), d) + d
                  + list.get(n - 1) : list.get(0);
    }

    public static void main(String[] args) {
        List<String> list = Arrays.asList(new String[]{"1","2","3"});
        System.out.println(Main.toString(list, ','));
    }

}

0
private String betweenComma(ArrayList<String> strings) {
    String united = "";
    for (String string : strings) {
        united = united + "," + string;
    }
    return united.replaceFirst(",", "");
}

-1

방법

String join(List<Object> collection, String delimiter){
    StringBuilder stringBuilder = new StringBuilder();
    int size = collection.size();
    for (Object value : collection) {
        size --;
        if(size > 0){
            stringBuilder.append(value).append(delimiter);
        }
    }

    return stringBuilder.toString();
}

용법

[1,2,3]의 배열이 주어지면

join(myArray, ",") // 1,2,3
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.