Как можно объединить элементы массива строкового типа, каждый с символом запятой, за исключением последнего элемента, к которому нужно присоединить «и»?

#javascript #arrays #string #algorithm

#javascript #массивы #строка #алгоритм

Вопрос:

У меня есть массив строк, который выглядит следующим образом.

 ['white t-shirt', 'blue jeans', 'red hat', 'brown glasses'...]
  

Мне нужно как-то поместить эти строки в следующий текст с помощью запятых, но перед последним элементом вместо запятой мне нужно установить и . Что-то вроде этого:

«Ваша карточка включает в себя белую футболку, синие джинсы, красную шляпу и коричневые очки, которые вы можете перейти на страницу оформления заказа»

Поскольку я собираюсь получать эти элементы массива из серверной части, мне нужно каким-то образом сделать динамическую генерацию приведенной выше строки. Как это может быть достигнуто, если это возможно, без цикла?

Комментарии:

1. Поправьте меня, если я ошибаюсь, но AFAIK согласно грамматике английского языка, перед «и» все равно должна быть запятая.

2. @YuryTarabanko Нет, фиксированной политики нет, исследуйте «оксфордскую запятую».

Ответ №1:

без временно сохраненных ссылок, но с изменением исходного strings массива …

 const strings = ['white t-shirt', 'blue jeans', 'red hat', 'brown glasses'];

console.log(
  [strings.pop(), strings.join(', ')].reverse().join(' and ')
);
console.log('mutated ... strings :', strings);  
 .as-console-wrapper { min-height: 100%!important; top: 0; }  

без временно сохраненных ссылок и на этот раз без изменения исходного strings массива …

 const strings = ['white t-shirt', 'blue jeans', 'red hat', 'brown glasses'];

console.log(
  [strings.slice(0, strings.length - 1).join(', '), ...strings.slice(-1)].join(' and ')
);
console.log('not mutated ... strings :', strings);  
 .as-console-wrapper { min-height: 100%!important; top: 0; }  

Ответ №2:

Вызывается часть Intl API Intl.ListFormat . Если вы хотите иметь правильное форматирование списка в соответствии с правилами локали, я бы посоветовал вам использовать его вместо ручного форматирования.

Например, перед «и» в указанном случае должна быть запятая.

 const strings = ['white t-shirt', 'blue jeans', 'red hat', 'brown glasses'];

const formatter = new Intl.ListFormat('en', { style: 'long', type: 'conjunction' });
console.log(formatter.format(strings));

const short = ['white t-shirt', 'blue jeans'];

console.log(formatter.format(short));  

Комментарии:

1. : P grammarly.com/blog /…

2. @malarres CLDR считает, что он должен быть там 😉

3. Спасибо за ссылку и пример. Я не знал об этом. Кое-что узнал.

4. Лучшая идея, но ее нельзя использовать в daily praxi, поскольку этот API не поддерживается Safari.

5. @VladislavLadicky Можно использовать polyfil formatjs.io/docs/polyfills/intl-listformat хотя

Ответ №3:

Вы можете использовать slice метод массива, чтобы сделать это просто.

 const arr = ['white t-shirt', 'blue jeans', 'red hat', 'brown glasses'];

const result = arr.slice(0, arr.length - 1).join(', ')   ' and '   arr.slice(-1)[0];

console.log(result);  

Комментарии:

1. Array.prototype.splice возвращает массив. Смешивать строку с массивами и полагаться на неявное принуждение не является хорошей практикой.

Ответ №4:

 strings = ['white t-shirt', 'blue jeans', 'red hat', 'brown glasses'];
lastString = strings.pop();
result = strings.join(', ')   ' and '   lastString;
  

Комментарии:

1. Изменение исходного массива — это, по крайней мере, плохая практика.

2. Довольно сложно исправить с помощью какой-то сложной гиперболы, такой как, ммм, ourStrings = […strings] и работать с ourStrings.

3. Ммм, хорошо, вы также знаете о деструктурировании. И это то, что вы называете «эффективным решением»?

Ответ №5:

Решение с reduce :

 const arr = ['white t-shirt', 'blue jeans', 'red hat', 'brown glasses']


const showList = () => {
  const OXFORD_COMMA=document.getElementById('oxford-comma').value;
  console.log(arr.reduce((acc,item,i) => (i<arr.length-1)?acc ', ' item:acc OXFORD_COMMA ' and ' item));
}  
 <p> Do you want to apply Oxford Comma rule? </p>
<select id="oxford-comma">
  <option value=",">Yes</option>
  <option value="">No</option>
</select>
<button type="button" onclick="showList()">output to console</button>  

ОБНОВЛЕНИЕ: теперь с опцией «Оксфордская запятая» благодаря @yuri-tarabanko 🙂

Комментарии:

1. Reduce возвращает массив. Я думаю, что это неподходящий метод для этой задачи.

2. «Метод reduce() выполняет функцию редуктора (которую вы предоставляете) для каждого элемента массива, в результате чего получается одно выходное значение». developer.mozilla.org/en-US/docs/Web/JavaScript/Reference /…

3. Неплохо. И? Использование метода reduce по-прежнему является самой слабой идеей здесь.

Ответ №6:

Это решение не изменяет ваш исходный массив, использует только строковые методы, поэтому не полагается на неявное принуждение, и оно очень хорошо поддерживается браузерами. Intl.ListFormat — лучшая идея, к сожалению, этот API не поддерживается ни Safari, ни Edge.

 let items = [
  'white t-shirt',
  'blue jeans',
  'red hat',
  'brown glasses'
]

let strings = items
  .join(', ')
  .replace(/,s*([^,] )$/, ' and $1')
  

Комментарии:

1. Используя это регулярное выражение, вы можете изменять данные. Последний элемент, содержащий запятую, будет изменен. Также должны иметь значение разборчивость кода и производительность.

2. Изменить данные? Как? О чем ты говоришь? Ваш код может изменять данные — исходный массив, а не мой.

3. Если последним элементом является «brown, очки», вы будете вставлять и в неправильном месте, преобразовывая это в «brown и очки», уничтожая данные, поскольку этого нигде нет в исходных данных