나는이 ArrayList
나는 완전히 String으로 출력 할 것인지. 본질적 toString
으로 탭으로 구분 된 각 요소를 사용하여 순서대로 출력하고 싶습니다 . 이 작업을 수행하는 빠른 방법이 있습니까? 루프를 반복하거나 각 요소를 제거하고 문자열에 연결할 수는 있지만 매우 느릴 것이라고 생각합니다.
나는이 ArrayList
나는 완전히 String으로 출력 할 것인지. 본질적 toString
으로 탭으로 구분 된 각 요소를 사용하여 순서대로 출력하고 싶습니다 . 이 작업을 수행하는 빠른 방법이 있습니까? 루프를 반복하거나 각 요소를 제거하고 문자열에 연결할 수는 있지만 매우 느릴 것이라고 생각합니다.
답변:
기본적으로 루프를 사용하여 반복하는 ArrayList
것이 유일한 옵션입니다.
이 코드를 사용하지 말고, 왜이 코드가 바람직하지 않은지, 대신 어떤 코드를 사용해야하는지 확인하려면이 답변의 맨 아래를 계속 읽으십시오.
ArrayList<String> list = new ArrayList<String>();
list.add("one");
list.add("two");
list.add("three");
String listString = "";
for (String s : list)
{
listString += s + "\t";
}
System.out.println(listString);
실제로, 문자열 연결은 javac
컴파일러가 어쨌든 일련의 append
작업으로 문자열 연결을 최적화 하기 때문에 괜찮을 것 StringBuilder
입니다. for
위 프로그램 의 루프에서 바이트 코드를 디스 어셈블하는 부분은 다음과 같습니다 .
61: new #13; //class java/lang/StringBuilder
64: dup
65: invokespecial #14; //Method java/lang/StringBuilder."<init>":()V
68: aload_2
69: invokevirtual #15; //Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
72: aload 4
74: invokevirtual #15; //Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
77: ldc #16; //String \t
79: invokevirtual #15; //Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
82: invokevirtual #17; //Method java/lang/StringBuilder.toString:()Ljava/lang/String;
보다시피, 컴파일러는를 사용하여 루프를 최적화 StringBuilder
하므로 성능에 큰 문제가되지 않습니다.
(두 번째 StringBuilder
로, 루프의 각 반복에서 인스턴스화되고 있으므로 가장 효율적인 바이트 코드가 아닐 수 있습니다. 명시 적으로 인스턴스화하고 사용하면 StringBuilder
성능이 향상됩니다.)
사실, 어떤 종류의 출력 (디스크 또는 화면)이 문자열 연결의 성능에 대해 걱정하는 것보다 적어도 속도가 느릴 것이라고 생각합니다.
편집 : 주석에서 지적했듯이 위의 컴파일러 최적화는 실제로 StringBuilder
각 반복마다 새 인스턴스를 작성합니다 . (이전에 언급 한 것입니다.)
가장 최적화 된 기술 은 루프 외부의 단일 객체 만 인스턴스화하기 때문에 Paul Tomblin 의 응답 입니다.StringBuilder
for
위의 코드를 다시 작성하여 다음을 수행하십시오.
ArrayList<String> list = new ArrayList<String>();
list.add("one");
list.add("two");
list.add("three");
StringBuilder sb = new StringBuilder();
for (String s : list)
{
sb.append(s);
sb.append("\t");
}
System.out.println(sb.toString());
이 바이트 코드에서 입증 된 것처럼 StringBuilder
루프 외부 에서 한 번만 인스턴스화하고 루프 append
내부의 메소드 를 두 번만 호출합니다 (인스턴스화 StringBuilder
및 루프 를 보여줍니다 ).
// Instantiation of the StringBuilder outside loop:
33: new #8; //class java/lang/StringBuilder
36: dup
37: invokespecial #9; //Method java/lang/StringBuilder."<init>":()V
40: astore_2
// [snip a few lines for initializing the loop]
// Loading the StringBuilder inside the loop, then append:
66: aload_2
67: aload 4
69: invokevirtual #14; //Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
72: pop
73: aload_2
74: ldc #15; //String \t
76: invokevirtual #14; //Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
79: pop
따라서 for
루프 내부 가 짧고 StringBuilder
각 반복마다 인스턴스를 생성 할 필요가 없으므로 실제로 손 최적화가 더 잘 수행되어야합니다 .
Java
또는 GeewaxAndroid
Java 8 이상에서 :
String listString = String.join(", ", list);
list
가 String 유형이 아닌 경우, 결합 콜렉터를 사용할 수 있습니다.
String listString = list.stream().map(Object::toString)
.collect(Collectors.joining(", "));
Android 에서이 작업을 수행하는 경우 TextUtils 라는 유용한 유틸리티 가 .join(String delimiter, Iterable)
있습니다.
List<String> list = new ArrayList<String>();
list.add("Item 1");
list.add("Item 2");
String joined = TextUtils.join(", ", list);
분명히 안드로이드 외부에서는 많이 사용하지는 않지만이 스레드에 추가 할 것이라고 생각했습니다 ...
TextUtils.join
소요 Object[]
, 나는 그것이 부르고 있다고 가정 것입니다 toString()
각 토큰에. 않습니다 PatientDetails
구현 toString()
? 그래도 문제가 해결되지 않으면 Separator
수업에 문제가있을 수 있습니다 .
org.apache.lang3.StringUtils
거의 동일합니다, 그래서 당신의 대답은 안드로이드 밖에서 나에게 많은 도움이되었습니다 :)
Apache Commons Lang을 다운로드하고 메소드를 사용하십시오.
StringUtils.join(list)
StringUtils.join(list, ", ") // 2nd param is the separator.
물론 직접 구현할 수도 있지만 코드는 완전히 테스트되었으며 아마도 가장 좋은 구현 일 것입니다.
저는 Apache Commons 라이브러리의 열렬한 팬이며 Java 표준 라이브러리에 큰 도움이된다고 생각합니다.
StringUtils.join(list.toArray(),"\t")
이것은 꽤 오래된 질문이지만 구아바 의 Joiner
수업을 사용하여 더 현대적인 답변을 추가 할 수 있다고 생각합니다 .
String joined = Joiner.on("\t").join(list);
읽기 쉽고 의미있는 문자열로 List 를 변경 하는 것은 실제로 모든 사람이 직면 할 수있는 일반적인 질문입니다.
사례 1 . 클래스 경로에 아파치의 StringUtils가있는 경우 (rogerdpack 및 Ravi Wallau에서와 같이) :
import org.apache.commons.lang3.StringUtils;
String str = StringUtils.join(myList);
사례 2 . JDK (7)의 방법 만 사용하려는 경우 :
import java.util.Arrays;
String str = Arrays.toString(myList.toArray());
혼자서 바퀴를 만들지 마십시오.이 한 줄 작업에는 루프를 사용하지 마십시오.
Arrays.toString(myList.toArray())
- 가장 쉽고 가장 간단한 솔루션
Arrays.toString(list.toArray())
쓰기는 쉽지만 비효율적입니다.
Java 5부터 빠른 원 라이너를 찾고 있다면 다음과 같이 할 수 있습니다.
myList.toString().replaceAll("\\[|\\]", "").replaceAll(", ","\t")
또한, 목적이 단지 내용을 인쇄하고 "\ t"에 대해 덜 염려한다면 다음과 같이하면됩니다.
myList.toString()
다음과 같은 문자열을 반환합니다
[str1, str2, str3]
ArrayList가 아닌 Array가있는 경우 다음과 같이 동일하게 수행 할 수 있습니다.
Arrays.toString(myList).replaceAll("\\[|\\]", "").replaceAll(", ","\t")
m
있는 n
도시의 가구에서 사람을 검색하라고 말하면 그 사람은 또는 이라고 말하지만 "이 나라에서이 사람을 찾으십시오"라고 말하면 즉시 말해 줄 수 있습니다. 또한 여기의 모든 알고리즘은 일반적으로 루프 내에 루프 가 없습니다 . x
O(mnx)
O(n^3)
O(n)
O(n)
그것을 반복하고 toString을 호출하십시오. 마법의 방법이 없으며, 있다면, 그것을 통해 루핑하는 것 이외의 덮개 아래에서 무엇을 할 것이라고 생각하십니까? 마이크로 최적화의 유일한 방법은 String 대신 StringBuilder를 사용하는 것입니다. 심지어 큰 승리는 아닙니다. 커버 아래에서 문자열을 연결하면 StringBuilder로 바뀌지 만 적어도 그렇게 작성하면 상황을 볼 수 있습니다.
StringBuilder out = new StringBuilder();
for (Object o : list)
{
out.append(o.toString());
out.append("\t");
}
return out.toString();
대부분의 Java 프로젝트에는 종종 Apache Commons 랭귀지가 있습니다. StringUtils.join () 메소드는 매우 훌륭하고 거의 모든 요구를 충족시키는 여러 가지 특징이 있습니다.
public static java.lang.String join(java.util.Collection collection,
char separator)
public static String join(Iterator iterator, String separator) {
// handle null, zero and one elements before building a buffer
Object first = iterator.next();
if (!iterator.hasNext()) {
return ObjectUtils.toString(first);
}
// two or more elements
StringBuffer buf =
new StringBuffer(256); // Java default is 16, probably too small
if (first != null) {
buf.append(first);
}
while (iterator.hasNext()) {
if (separator != null) {
buf.append(separator);
}
Object obj = iterator.next();
if (obj != null) {
buf.append(obj);
}
}
return buf.toString();
}
매개 변수 :
collection- 결합 할 값의 콜렉션. null의 경우도있다
separator- 사용하는 단락 문자
리턴 : 결합 된 문자열, 널 (null) 반복기 입력 인 경우 널
이후 : 2.3
join(...)
메소드에는 배열과 컬렉션 모두에 대한 변형 이 있으므로 매우 좋습니다 .
Android에는 http://developer.android.com/reference/android/text/TextUtils.html 을 사용할 수있는 TextUtil 클래스가 있습니다.
String implode = TextUtils.join("\t", list);
후행 분리 문자를 처리하는 우아한 방법은 Class Separator 를 사용하는 것입니다.
StringBuilder buf = new StringBuilder();
Separator sep = new Separator("\t");
for (String each: list) buf.append(sep).append(each);
String s = buf.toString();
Class Separator의 toString 메소드 는 첫 번째 호출을 제외하고 구분자를 리턴합니다 . 따라서 우리는 후행 (또는이 경우) 선행 구분 기호없이 목록을 인쇄합니다.
Java 8에서는 간단합니다. 정수 목록은 예를 참조하십시오.
String result = Arrays.asList(1,2,3).stream().map(Object::toString).reduce((t, u) -> t + "\t" + u).orElse("");
또는 여러 줄 버전 (읽기가 더 간단 함) :
String result = Arrays.asList(1,2,3).stream()
.map(Object::toString)
.reduce((t, u) -> t + "\t" + u)
.orElse("");
String result = Arrays.asList(1,2,3).stream()
.map(Object::toString)
.collect(Collectors.joining("\t"));
filter
. 결국 코드를 읽는 것이 훨씬 쉽습니다.
String
마찬가지로 작동합니다. 의 목록에 Integer
문제가있는 경우
그것은 O(n)
어느 쪽이든 알고리즘입니다 (목록을 여러 하위 목록으로 나누는 다중 스레드 솔루션을 수행하지 않은 한, 그것이 당신이 요구하는 것이라고 생각하지 않습니다).
StringBuilder
아래와 같이 a 를 사용하십시오 .
StringBuilder sb = new StringBuilder();
for (Object obj : list) {
sb.append(obj.toString());
sb.append("\t");
}
String finalString = sb.toString();
는 StringBuilder
당신이 다시 인스턴스화 수 없기 때문에 훨씬 빨리 문자열 연결보다 것이다 String
각 연결 개체를.
Android에 있고 아직 Jack을 사용하지 않는 경우 (예 : Instant Run에 대한 지원이 여전히 부족하기 때문에) 결과 문자열의 형식을보다 세밀하게 제어하려는 경우 (예 : 줄 바꿈 문자를 다음과 같이 사용하려는 경우) 요소 나누기)를 사용하고 StreamSupport 라이브러리를 사용하여 Java7 또는 이전 버전의 컴파일러에서 스트림을 사용하는 경우 다음과 같이 사용할 수 있습니다 (이 방법을 내 ListUtils 클래스에 넣습니다).
public static <T> String asString(List<T> list) {
return StreamSupport.stream(list)
.map(Object::toString)
.collect(Collectors.joining("\n"));
}
물론 목록 객체의 클래스에 toString ()을 구현해야합니다.
reduce
문자열 연결에는 사용 이 매우 비효율적입니다. return StreamSupport.stream(list).map(Object::toString).collect(joining("\n"))
내부적으로 사용 하는 Java 8 방식으로해야 합니다 StringJoiner
. streamsupport로이 작업을 수행 할 수없는 이유는 없습니다 .
Optional#get
빈 목록을 전달하면 코드가 끔찍하게 실패한다는 것입니다 .
마지막 요소 다음에 마지막 \ t를 원하지 않으면 인덱스를 사용하여 확인해야하지만 목록이 RandomAccess를 구현할 때이 "작동"(즉, O (n)) 만 기억하십시오.
List<String> list = new ArrayList<String>();
list.add("one");
list.add("two");
list.add("three");
StringBuilder sb = new StringBuilder(list.size() * apprAvg); // every apprAvg > 1 is better than none
for (int i = 0; i < list.size(); i++) {
sb.append(list.get(i));
if (i < list.size() - 1) {
sb.append("\t");
}
}
System.out.println(sb.toString());
가장 좋은 방법은 아니지만 우아한 방법 일 수 있습니다.
Arrays.deepToString (Arrays.asList ( "Test", "Test2")
import java.util.Arrays;
public class Test {
public static void main(String[] args) {
System.out.println(Arrays.deepToString(Arrays.asList("Test", "Test2").toArray()));
}
}
산출
[테스트, 테스트 2]
당신이 사용하는 경우 이클립스 컬렉션 , 당신은 사용할 수있는 makeString()
방법을.
ArrayList<String> list = new ArrayList<String>();
list.add("one");
list.add("two");
list.add("three");
Assert.assertEquals(
"one\ttwo\tthree",
ArrayListAdapter.adapt(list).makeString("\t"));
당신이 당신을 변환 할 수 있습니다 경우 ArrayList
A를 FastList
, 당신은 어댑터를 제거 얻을 수 있습니다.
Assert.assertEquals(
"one\ttwo\tthree",
FastList.newListWith("one", "two", "three").makeString("\t"));
참고 : 저는 Eclipse Collections의 커미터입니다.
한 줄에 : [12,0,1,78,12]에서 12 1 78 12
String srt= list.toString().replaceAll("\\[|\\]|,","");
println 을 사용하는 대신 탭을 사용하여 분리 하려면 print 를 사용할 수 있습니다
ArrayList<String> mylist = new ArrayList<String>();
mylist.add("C Programming");
mylist.add("Java");
mylist.add("C++");
mylist.add("Perl");
mylist.add("Python");
for (String each : mylist)
{
System.out.print(each);
System.out.print("\t");
}
추가 리소스에 의존하는 몇 가지 예를 보았지만 이것이 가장 간단한 해결책 인 것처럼 보입니다. (내 프로젝트에서 사용한 것) 기본적으로 ArrayList에서 Array로 변환 한 다음 List로 변환하는 것입니다 .
List<Account> accounts = new ArrayList<>();
public String accountList()
{
Account[] listingArray = accounts.toArray(new Account[accounts.size()]);
String listingString = Arrays.toString(listingArray);
return listingString;
}
이것은 지금까지 꽤 오래된 대화이며 아파치 커먼즈는 이제 내부적으로 StringBuilder를 사용하고 있습니다. http://commons.apache.org/lang/api/src-html/org/apache/commons/lang/StringUtils.html#line. 3045
이것은 우리가 알고있는 것처럼 성능을 향상 시키지만, 성능이 중요하다면 사용 된 방법이 다소 비효율적 일 수 있습니다. 인터페이스가 유연하고 다른 컬렉션 유형에서 일관된 동작을 허용하는 반면 원래 질문의 컬렉션 유형 인 목록에는 다소 비효율적입니다.
나는 전통적인 for 루프에서 단순히 요소를 반복함으로써 피할 수있는 약간의 오버 헤드가 발생한다는 점에서 이것을 근거로합니다. 대신, 동시 수정, 메소드 호출 등을 확인하는 장면 뒤에서 발생하는 몇 가지 추가 사항이 있습니다. 반면 강화 된 for 루프는 반복자가 Iterable 객체 (목록)에서 사용되므로 동일한 오버 헤드가 발생합니다.
이 기능은 어떻습니까?
public static String toString(final Collection<?> collection) {
final StringBuilder sb = new StringBuilder("{");
boolean isFirst = true;
for (final Object object : collection) {
if (!isFirst)
sb.append(',');
else
isFirst = false;
sb.append(object);
}
sb.append('}');
return sb.toString();
}
그것은 모든 유형의 컬렉션에서 작동합니다 ...