2016-03-04 3 views
6

Использование только стандартной библиотеки Java, что является простым механизмом для объединения строк до предела и добавления многоточия, когда предел приводит к более короткой строке?Объединение строк с ограничением

Эффективность желательно. Объединение всех строк, а затем использование String.substring() может потреблять чрезмерную память и время. Механизм, который может использоваться в конвейере потока Java 8, является предпочтительным, так что строки за пределом никогда не могут быть созданы.

Для моих целей, я был бы счастлив с лимитом, выраженной в любой:

  • Максимальное количество строк, чтобы присоединиться к
  • Максимальное количество символов в результате, в том числе любые символы разделителей.

Например, это один из способов обеспечить максимальное количество присоединенных строк в Java 8 со стандартной библиотекой. Есть ли более простой подход?

final int LIMIT = 8; 

Set<String> mySet = ...; 
String s = mySet.stream().limit(LIMIT).collect(Collectors.joining(", ")); 
if (LIMIT < mySet.size()) { 
    s += ", ..."; 
} 
+0

Этот вопрос НЕ просит «рекомендовать или найти книгу, инструмент, библиотеку программного обеспечения, учебник или другой ресурс вне сайта». –

ответ

8

Вы можете написать свой заказ коллекционер для этого. Это один основан на another I wrote for a similar case:

private static Collector<String, List<String>, String> limitingJoin(String delimiter, int limit, String ellipsis) { 
    return Collector.of(
       ArrayList::new, 
       (l, e) -> { 
        if (l.size() < limit) l.add(e); 
        else if (l.size() == limit) l.add(ellipsis); 
       }, 
       (l1, l2) -> { 
        l1.addAll(l2.subList(0, Math.min(l2.size(), Math.max(0, limit - l1.size())))); 
        if (l1.size() == limit) l1.add(ellipsis); 
        return l1; 
       }, 
       l -> String.join(delimiter, l) 
      ); 
} 

В этом коде, мы держим ArrayList<String> всех encoutered струнных. Когда элемент принят, размер текущего списка проверяется на пределе: строго меньше его, добавляется элемент; равный ему, добавляется многоточие. То же самое делается для части объединителя, что немного сложнее, потому что нам нужно правильно обрабатывать размеры подсписок, чтобы не переходить через лимит. Наконец, финишер просто присоединяется к этому списку с данным разделителем.

Эта реализация работает для параллельных потоков. Он будет удерживать элементы заголовка Stream in encounter order. Обратите внимание, что он потребляет все элементы в потоке, даже если ни один элемент не добавляется после достижения предела.

Рабочий пример:

List<String> list = Arrays.asList("foo", "bar", "baz"); 
System.out.println(list.stream().collect(limitingJoin(", ", 2, "..."))); // prints "foo, bar, ..." 
+0

Спасибо. При необходимости использования всех элементов в потоке можно было бы, если необходимо, вставить 'limit (LIMIT + 1)' перед 'collect()'. –

+1

@ AndyThomas Да. Но сам коллекционер не является короткозамкнутым. – Tunaki

+1

+1 для приятной реализации стоечного станка с числовой строкой. Столбец с числовыми символами будет более сложным. – Andreas

1

Используя только стандартную библиотеку Java

Я не верю, что есть что-то там, что может делать то, что вы спрашиваете.

Вам необходимо написать собственный Collector. Это будет не так сложно, поэтому я не понимаю, почему писать собственное было бы проблемой.

+0

Это произошло со мной. Я мог бы «ограничивать (LIMIT + 1)», чтобы пересекать только часть потока, но все же позволяет пользовательскому сборщику знать, что предел достигнут. Был надеется, что было что-то более простое, что я пропустил. –

+0

Ограничение * числа * строк, кажется мне бессмысленным. Он должен ограничивать * длину * результата, что означает, что 'limit()' не является ответом. – Andreas

+0

Конечно, в некоторых случаях это правда. Однако у меня есть случай, когда строки известный априорный o быть коротким; точный предел в символах не требуется; и я хотел бы включить только целые строки. –

5

При использовании стороннего кода не вариант для спрашивающего, это может быть приемлемым для других читателей. Даже при написании пользовательского коллектора у вас все еще есть проблема: весь вход будет обработан, поскольку стандартные коллекторы не могут закорачиваться (в частности, невозможно обработать бесконечный поток). Моя библиотека StreamEx расширяет концепцию коллекционеров, что позволяет создавать коллекторы с коротким замыканием. Joining коллектор также легко обеспечивается:

StreamEx.of(mySet).collect( 
    Joining.with(", ").ellipsis("...").maxChars(100).cutAfterDelimiter()); 

Результат гарантирован не должен превышать 100 символов. Можно использовать различные стратегии подсчета: вы можете ограничить символами, точками кода или графемами (объединение символов Юникода не будет засчитано). Также вы можете вырезать результат в любой позиции («Первая запись, вторая строка ...«) или после слова (« Первая запись, вторая ... ») или после разделителя (« Первая запись, ... ») или перед разделителем (« Первая запись, вторая запись ... »). для параллельного потока, хотя, вероятно, не очень эффективно в упорядоченном случае.

+0

Выглядит неплохо! Позволяет читаемое выражение намерения. –

Смежные вопросы