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
isがどのように実装されているか(AbstractCollection
から継承)、 Java 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(", ");
}
}
最後の項目の後のコンマを避けるために、ループを早期に終了します。ところで:これは私が「(このコレクション)」を見たことを思い出すのは初めてです。それを引き起こすコードは次のとおりです。
List l = new LinkedList();
l.add(l);
System.out.println(l);
予期しないライブラリ(regexp?)を使用している場合でも、ソリューションを歓迎します。また、Java(たとえば、Python/Rubyにはintersperse関数があると思います-how isthat実装?).
明確化:ライブラリでは、標準Javaライブラリ。他のライブラリについては、他の言語で検討します。それらがどのように実装されているかを知りたい。
[〜#〜] edit [〜#〜]ツールキットは同様の質問に言及しました: Javaの拡張forループの最後の反復
そしてもう一つ: ループの最後の要素は別の扱いに値しますか?
StringJoiner
classを使用:
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();
#28552 も参照してください
String delim = "";
for (Item i : list) {
sb.append(delim).append(i);
delim = ",";
}
org.Apache.commons.lang3.StringUtils.join(list,",");
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;
。
Joiner.on(",").join(myList)
Joiner 。
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)
JavaのList toString実装に基づく:
Iterator i = list.iterator();
for (;;) {
sb.append(i.next());
if (! i.hasNext()) break;
ab.append(", ");
}
次のような文法を使用します。
List --> (Item , )* Item
ファーストベースではなくラストベースにすることで、リストの終わりをチェックするのと同じテストでskip-commaをチェックできます。これは非常にエレガントだと思いますが、明確さについてはわかりません。
Java 8:を使用してこれを達成するためのかなりの方法があります。
List<String> list = Arrays.asList(array);
String joinedString = String.join(",", list);
String delimiter = ",";
StringBuilder sb = new StringBuilder();
for (Item i : list) {
sb.append(delimiter).append(i);
}
sb.toString().replaceFirst(delimiter, "");
for(int i=0, length=list.size(); i<length; i++)
result+=(i==0?"":", ") + list.get(i);
Foreachループの1つのオプションは次のとおりです。
StringBuilder sb = new StringBuilder();
for(String s:list){
if (sb.length()>0) sb.append(",");
sb.append(s);
}
StringBuffer result = new StringBuffer();
for(Iterator it=list.iterator; it.hasNext(); ) {
if (result.length()>0)
result.append(", ");
result.append(it.next());
}
更新:Dave Webbがコメントで述べたように、リストの最初の項目が空の文字列の場合、これは正しい結果を生成しない可能性があります。
私は通常これを行います:
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 implementation;)に従って、今後このチェックを行うと思いますが)
JVMで実行されるGroovyを使用できる場合:
def list = ['a', 'b', 'c', 'd']
println list.join(',')
( here からの私自身の回答のコピーペースト)ここで説明したソリューションの多くは、特に外部ライブラリに依存しているものよりも少し上に、私見です。私がいつも使用していたコンマ区切りリストを実現するための、すっきりした、明確なイディオムがあります。条件(?)演算子に依存しています。
Edit:元のソリューションは正しいが、コメントによると最適ではない。もう一度試してください:
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() ? "," : "");
私は通常バージョン3に似たものを使用します。c/ c ++/bash/...でうまく動作します:P
私はこのソリューションが好きです:
String delim = " - ", string = "";
for (String item : myCollection)
string += delim + item;
string = string.substring(delim.length());
StringBuilderも利用できると思います。
これは非常に短く、非常に明確ですが、私の感性に忍び寄る恐怖を与えます。特に文字列(charではない)の場合、異なる区切り文字に適応するのも少し厄介です。
for (Item i : list)
sb.append(',').append(i);
if (sb.charAt(0)==',') sb.deleteCharAt(0);
インスピレーション: Javaの拡張forループの最後の反復
私はそれをコンパイルしませんでした...しかし動作するはずです(または動作に近い).
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());
}
区切り文字は「、」なので、次のいずれかを使用できます。
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;}
}
}
あなたの区切り文字が何か他のものである場合、これはあなたのために機能しません。
StringBuffer sb = new StringBuffer();
for (int i = 0; i < myList.size(); i++)
{
if (i > 0)
{
sb.append(", ");
}
sb.append(myList.get(i));
}
少し前にブログで見つけたこのアプローチが好きです。残念ながら、ブログの名前/ 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);
}
In Pythonその簡単
"、"。join(yourlist)
C#では、Stringクラスに静的メソッドがあります
String.Join( "、"、yourlistofstrings)
申し訳ありませんが、Javaについてはわかりませんが、他の言語について尋ねたのでパイプアップすると思いました。Javaにも似たようなものがあるはずです。
私の意見では、これは読んで理解するのが最も簡単です:
StringBuilder sb = new StringBuilder();
for(String string : strings) {
sb.append(string).append(',');
}
sb.setLength(sb.length() - 1);
String result = sb.toString();
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();
}
これまでのところ、答えはどれも再帰を使用していません...
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, ','));
}
}
区切り文字列を無条件に追加し、ループの後、最後の余分な区切り文字を削除することもできます。次に、最初に「リストが空の場合、この文字列を返す」を使用すると、最後のチェックを回避できます(空のリストから文字を削除できないため)
だから質問は本当に:
「ループとifを考えると、これらをまとめる最も明確な方法は何だと思いますか?」
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;
}
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]);
このアイデアの使用: ループ内の最後の要素は別の扱いに値しますか?
private String betweenComma(ArrayList<String> strings) {
String united = "";
for (String string : strings) {
united = united + "," + string;
}
return united.replaceFirst(",", "");
}