web-dev-qa-db-ja.com

Javaでコンマと「and」を使用してList <String>を結合する

リストを与えられた

List<String> l = new ArrayList<String>();
l.add("one");
l.add("two");
l.add("three");

メソッドがあります

String join(List<String> messages) {
        if (messages.isEmpty()) return "";
        if (messages.size() == 1) return messages.get(0);
        String message = "";
        message = StringUtils.join(messages.subList(0, messages.size() -2), ", ");
        message = message + (messages.size() > 2 ? ", " : "") + StringUtils.join(messages.subList(messages.size() -2, messages.size()), ", and ");
        return message;
    }

これは、lに対して「1、2、3」を生成します。私の質問は、同じことを行う標準の(Apache-commons)メソッドはありますか?

WhatEverUtils.join(l, ", ", ", and ");

明確にするために。私の問題は、この方法が機能しないことです。それは私が望んでいるように機能し、テストされ、すべてが順調です。私の問題は、そのような機能を実装するApacheコモンのようなモジュールが見つからなかったことです。私がこれを必要とする最初の人になることはできないので、それは私を驚かせます。

しかし、その後、おそらく他の誰もがやった

StringUtils.join(l, ", ").replaceAll(lastCommaRegex, ", and");
48
slipset

Java 8では、次のようにString.join()を使用できます。

Collection<String> elements = ....;
String result = String.join(", ", elements);
52
Ali Dehghani

join from: org.Apache.commons.lang.StringUtils

例:

StringUtils.join(new String[] { "one", "two", "three" }, ", "); // one, two, three

「and」または「and」を使用するには、最後のカンマを単純に置き換えることができます。

17
lukastymo

この目的でGoogleコレクションを使用するのが好きです。端正で非常に便利:

Joiner.on(",").join(myList)

この種のコードは何度も記述されてきたので、特定の実装ロジックを実装するのではなく、自由にすべきです。

Mavenを使用する場合、依存関係は次のとおりです。

<dependency>
  <groupId>com.google.collections</groupId>
  <artifactId>google-collections</artifactId>
  <version>1.0</version>
</dependency>

他の素晴らしいクールな機能もたくさんあります!

編集:完全を期すために、これは「1、2、3」のリストを作成します。

List<String> originalList = Arrays.asList("one", "two", "three");
Joiner.on(", ").join(originalList.subList(0, originalList.size() - 1))
  .concat(", and ").concat(originalList.get(originalList.size() - 1));
14

Java 8を使用すると、ジョイナーでストリームを使用できます。

Collection<String> strings;
...
String commaDelimited = strings.stream().collect(Collectors.joining(","));
// use strings.parallelStream() instead, if you think
//   there are gains to be had by doing fork/join
11
CppNoob

他の回答では、「最後のコンマの置き換え」について説明しています。これは、最後の用語自体にコンマが含まれている場合には安全ではありません。

ライブラリを使用するのではなく、JDKコードの1行(とはいえ)を使用できます。

public static String join(List<String> msgs) {
    return msgs == null || msgs.size() == 0 ? "" : msgs.size() == 1 ? msgs.get(0) : msgs.subList(0, msgs.size() - 1).toString().replaceAll("^.|.$", "") + " and " + msgs.get(msgs.size() - 1);
}

すべてのEdgeケースを処理するこのコードの live demo を参照してください。


参考までに、より読みやすい2ライナーを次に示します。

public static String join(List<String> msgs) {
    int size = msgs == null ? 0 : msgs.size();
    return size == 0 ? "" : size == 1 ? msgs.get(0) : msgs.subList(0, --size).toString().replaceAll("^.|.$", "") + " and " + msgs.get(size);
}
4
Bohemian

英語の文法出力を生成するには、文字列のリストを連結するときに考慮すべき3つのケースがあります。

  1. 「A」

  2. 「AとB」

  3. 「A、B、C。

これは、標準のJavaまたは以下のようなGuavaを使用して実現できます。ソリューションは基本的に同じであり、使用するものは好み次第です。

import com.google.common.base.Joiner;
import com.google.common.collect.ImmutableList;

import org.junit.Test;

import Java.util.List;

import static org.junit.Assert.assertEquals;

public class JoinListTest {

    @Test
    public void test_join() {
        // create cases (don't need to use ImmutableList builder from guava)
        final List<String> case1 = new ImmutableList.Builder<String>().add("A").build();
        final List<String> case2 = new ImmutableList.Builder<String>().add("A", "B").build();
        final List<String> case3 = new ImmutableList.Builder<String>().add("A", "B", "C").build();
        // test with standard Java
        assertEquals("A", joinListGrammaticallyWithJava(case1));
        assertEquals("A and B", joinListGrammaticallyWithJava(case2));
        assertEquals("A, B, and C", joinListGrammaticallyWithJava(case3));
        // test with guava
        assertEquals("A", joinListGrammaticallyWithGuava(case1));
        assertEquals("A and B", joinListGrammaticallyWithGuava(case2));
        assertEquals("A, B, and C", joinListGrammaticallyWithGuava(case3));
    }

    private String joinListGrammaticallyWithJava(final List<String> list) {
        return list.size() > 1
                ? String.join(", ", list.subList(0, list.size() - 1))
                    .concat(String.format("%s and ", list.size() > 2 ? "," : ""))
                    .concat(list.get(list.size() - 1))
                : list.get(0);
    }

    private String joinListGrammaticallyWithGuava(final List<String> list) {
        return list.size() > 1
                ? Joiner.on(", ").join(list.subList(0, list.size() - 1))
                    .concat(String.format("%s and ", list.size() > 2 ? "," : ""))
                    .concat(list.get(list.size() - 1))
                : list.get(0);
    }

}
4
Abtin Gramian

結合された文字列にandを追加することをサポートできるApache Stringジョイナを知りません。

これは、あなたが尋ねたことをするテストされていないコードです:

public static String join(String separator, List<String> mList, boolean includeAndInText) {
    StringBuilder sb = new StringBuilder();
    int count = 0;

    for (String m: mList) {
        if (includeAndInText && (count + 1 != mList.size())) {
            sb.append (" and ");
        }

        sb.append(m);
        count++;
        if (count < mList.size()) {
            sp.append(separator);
        }       
    }

    return sb.toString();
}
0
Buhake Sindi