Java-еквівалент імплоду PHP (',', array_filter (array ()))


75

Я часто використовую цей фрагмент коду в PHP

$ordine['address'] = implode(', ', array_filter(array($cliente['cap'], $cliente['citta'], $cliente['provincia'])));

Він очищає порожні рядки і приєднує їх знаком ",". Якщо залишився лише один, це не додає зайвої зайвої коми. У кінці не додається кома. Якщо жоден не залишається, він повертає порожній рядок.

Таким чином я можу отримати один із наступних результатів

""
"Street abc 14"
"Street abc 14, 00168"
"Street abc 14, 00168, Rome"

Яка найкраща реалізація Java (менше коду) в Java без необхідності додавати зовнішні бібліотеки (проектування для Android)?



FYI для цього прикладу вам знадобиться зовнішня бібліотека (import org.apache.commons.lang.StringUtils;), але я все одно рекомендую використовувати цей метод
Owen Gerig

dfreeman не робить те, що мені потрібно, не додаючи коми, де потрібно
max4ever

4
не можу повірити, що у Java ще цього немає. кожна інша мова це робить.
OneSolitaryNoob

Чи можете ви змінити знак прийняття? stackoverflow.com/a/11248692/871050 ця відповідь є найбільш правильною тут.
Привид

Відповіді:


90

Оновлена ​​версія за допомогою Java 8 (оригінал в кінці допису)

Якщо вам не потрібно фільтрувати будь-які елементи, які ви можете використовувати


З Java 8 ми можемо використовувати StringJoiner(замість спочатку використовуваного StringBulder) та спростити наш код.
Також, щоб уникнути перекомпіляції " *"регулярного виразу в кожному виклику, matches(" *")ми можемо створити окремий Шаблон, який буде містити свою скомпільовану версію в якомусь полі та використовувати її за потреби.

private static final Pattern SPACES_OR_EMPTY = Pattern.compile(" *");
public static String implode(String separator, String... data) {
    StringJoiner sb = new StringJoiner(separator);
    for (String token : data) {
        if (!SPACES_OR_EMPTY.matcher(token).matches()) {
            sb.add(token);
        }
    }
    return sb.toString();
}   

З потоками наш код може виглядати так.

private static final Predicate<String> IS_NOT_SPACES_ONLY = 
        Pattern.compile("^\\s*$").asPredicate().negate();

public static String implode(String delimiter, String... data) {
    return Arrays.stream(data)
            .filter(IS_NOT_SPACES_ONLY)
            .collect(Collectors.joining(delimiter));
}

Якщо ми використовуємо потоки, ми можемо використовувати filterелементи, які Predicate. У цьому випадку ми хочемо, щоб предикат приймав рядки, які є не лише пробілами - іншими словами, рядок повинен містити непробільний символ.

Ми можемо створити такий предикат із шаблону. Створений таким чином предикат буде приймати будь-які рядки, які будуть містити підрядок, якому може відповідати регулярний вираз (тому, якщо регулярний вираз буде шукати"\\S" предикат буде приймати рядки , як "foo ", " foo bar ", "whatever", але не братиме " "ні " ").

Тож ми можемо використовувати

Pattern.compile("\\S").asPredicate();

або, можливо, трохи більш описове, заперечення рядків, які є лише пробілами або порожніми

Pattern.compile("^\\s*$").asPredicate().negate();

Далі, коли фільтр видалить усі порожні або містять лише пробіли рядки, які ми можемо collect залишити елементи. Завдяки Collectors.joiningми можемо вирішити, який роздільник використовувати.


Оригінальна відповідь (до Java 8)

public static String implode(String separator, String... data) {
    StringBuilder sb = new StringBuilder();
    for (int i = 0; i < data.length - 1; i++) {
    //data.length - 1 => to not add separator at the end
        if (!data[i].matches(" *")) {//empty string are ""; " "; "  "; and so on
            sb.append(data[i]);
            sb.append(separator);
        }
    }
    sb.append(data[data.length - 1].trim());
    return sb.toString();
}

Ви можете використовувати це як

System.out.println(implode(", ", "ab", " ", "abs"));

або

System.out.println(implode(", ", new String[] { "ab", " ", "abs" }));

Вихідні дані ab, abs


так, його зручніше використовувати, оскільки вам не потрібно створювати масив, і я не знав, що ви можете використовувати String, String ...
max4ever

це не працює добре, коли дані мають довжину 1 xD, я використовую цей sb.append (дані [0]); for (int i = 1; i <(data.length); i ++) {//data.length - 1 => не додавати роздільник в кінці if ((data [i]! = null) &&! data [i ] .matches ("*")) {// порожній рядок - ""; ""; ""; і так далі sb.append (роздільник); sb.append (дані [i]); }}
max4ever

1
@ max4ever ви могли б показати якийсь приклад? Я протестував на, System.out.println(implode(", ", "X"))і це, здається, працює нормально.
Пшемо

79

Чому так серйозно? Спробуйте StringUtils.join(new String[] {"Hello", "World", "!"}, ", ")!


30
StringUtils - це зовнішня бібліотека
max4ever

28
це зроблено Apache, усі використовують це ... Я роблю це по-
богданово

10
Чудово, що ви «робите це по-своєму», якщо бібліотека вже доступна. Якщо це не так, а) ви повинні знати, що це зовнішній б) де / як ви можете його отримати та в) чи дозволено вам це робити. Гра в некорпоративний ковбой лише позбавляє вас від c)
Зефіро,

3
Зовнішню бібліотеку можна знайти тут: commons.apache.org/proper/commons-lang
Алан Б. Ді

19

Ось відповідь для Android, яка може бути корисною для деяких:

String combined = TextUtils.join(",", new String[]{"Red", "Green", "Blue"});

// Result => Red,Green,Blue

Обов’язково імпортуйте клас TextUtils:

import android.text.TextUtils;

17

Вам доведеться додати свої рядки до ArrayList, видалити порожні та відформатувати його відповідно:

public static String createAddressString( String street, String zip_code, String country) {
    List<String> list = new ArrayList<String>();
    list.add( street);
    list.add( zip_code);
    list.add( country);

    // Remove all empty values
    list.removeAll(Arrays.asList("", null));

    // If this list is empty, it only contained blank values
    if( list.isEmpty()) {
        return "";
    }

    // Format the ArrayList as a string, similar to implode
    StringBuilder builder = new StringBuilder();
    builder.append( list.remove(0));

    for( String s : list) {
        builder.append( ", ");
        builder.append( s);
    }

    return builder.toString();
}

Крім того, якщо у вас був String[]масив рядків, ви можете легко додати їх до ArrayList:

String[] s;
List<String> list = new ArrayList<String>( Arrays.asList( s));

У реалізації функції implode ви модифікуєте вихідний список (неправильно) і видаляєте перший елемент ArrayList (дорогий). Крім того, запропоноване перетворення з масиву - чому б не просто asList? У будь-якому випадку, якщо введенням є List, найпростіший спосіб зробити це самостійно - це, мабуть, використання ітератора списку з читанням (і додаванням) першого елемента попереднього циклу, а потім ітерацією решти. Вибачте, але я повинен дати вам -1.
Vlasec

Що стосується видалення нульових та порожніх рядків, ви також можете видалити їх з вихідних даних, не змінюючи вихідний список - але, звичайно, вам знадобиться цикл для пошуку першого непорожнього елемента, а не простий if. Крім того, ваше рішення не працює в порожньому списку - remove(0)викидає файл IndexOutOfBoundsException.
Vlasec

@Vlasec - Оригінального списку немає, у методі я створюю свій власний локальний список, тому ваш аргумент недійсний, оскільки введеним є не список, а три значення String. Також перевіряється, чи список порожній, що є ще одним недійсним аргументом, який ви подали.
nickb

Ви технічно правильні. Однак вам все-таки слід спробувати навчити найкращих практик тут. Деякий зелений ріг може застосувати вашу техніку та зіпсувати існуючий список. Крім того, це не особливо ефективний або елегантний підхід, навіть якщо ви можете знищити колекцію.
Vlasec

@Vlasec - Ви маєте право на свою думку, проте я не погоджуюсь. Ваш коментар, що це не ефективне чи елегантне рішення, ґрунтується виключно на думці.
nickb

2

Простий Імплоде

public static String implode(String glue, String[] strArray)
{
    String ret = "";
    for(int i=0;i<strArray.length;i++)
    {
        ret += (i == strArray.length - 1) ? strArray[i] : strArray[i] + glue;
    }
    return ret;
}

Ви можете створити для нього перевантаження ..

Наведений вище еквівалент php імплодіює.
Ось що ви хочете:

import java.lang.*
public static String customImplode(String glue, String[] strArray)
{
    String ret = "";
    for(int i=0;i<strArray.length;i++)
    {
        if (strArray[i].trim() != "")
            ret += (i == strArray.length - 1) ? strArray[i] : strArray[i] + glue;
    }
    return ret;
}

2
він додає клей до кінця, і він не пропускає порожні рядки
max4ever

@ max4ever Я думаю, це ваша відповідь, чи не так?
Сороуш Хосраві

все ще не пропускає порожні рядки
max4ever

@ max4ever Будь ласка, очистіть своє питання. Ви хочете користувацький метод або еквівалент php implode?! \
Сороуш Хосраві

вам потрібно додати (TextUtils.isEmpty (strArray [i])? "": strArray [i] + клей, щоб він працював
max4ever

2

Використання потоків (для Java 8 та пізніших версій) було б альтернативним можливим рішенням для цього.

Вам потрібно імпортувати

java.util.stream.Collectors;

використовувати процес приєднання

Ви можете використовувати:

Arrays.asList("foo","bar").stream().collect(Collectors.joining(","));

для досягнення бажаного результату.


1

Ось моя імпладетна реалізація:

/**
 * Implodes the specified items, gluing them using the specified glue replacing nulls with the specified
 * null placeholder.
 * @param glue              The text to use between the specified items.
 * @param nullPlaceholder   The placeholder to use for items that are <code>null</code> value.
 * @param items             The items to implode.
 * @return  A <code>String</code> containing the items in their order, separated by the specified glue.
 */
public static final String implode(String glue, String nullPlaceholder, String ... items) {
    StringBuilder sb = new StringBuilder();
    for (String item : items) {
        if (item != null) {
            sb.append(item);
        } else {
            sb.append(nullPlaceholder);
        }
        sb.append(glue);
    }
    return sb.delete(sb.length() - glue.length(), sb.length()).toString();
}

1
public static String implode(List<String> items, String separator) {

        if (items == null || items.isEmpty()) {
            return null;
        }
        String delimiter = "";
        StringBuilder builder = new StringBuilder();
        for (String item : items) {
            builder.append(delimiter).append(item);
            delimiter = separator;
        }
        return builder.toString();
    }

Пояснення буде в порядку.
Пітер Мортенсен

0

Використовуйте цю просту функцію:

private String my_implode(String spacer, String[] in_array){

    String res = "";

    for (int i = 0 ; i < in_array.length ; i++) {

        if (!res.equals("")) {
            res += spacer;
        }
        res += in_array[i];
    }

    return res;
}

Використання:

data_arr = {"d1", "d2", "d3"};
your_imploded_text = my_implode(",", data_arr);
// Output: your_imploded_text = "d1,d2,d3"
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.