Присоединяйтесь к массиву запятыми и "и"

Я хочу преобразовать массив ['one', 'two', 'three', 'four'] в one, two, three and four

Обратите внимание, что первые элементы имеют запятую, и, но есть слово and между предпоследними один и последним.

Лучшее решение, которое я придумал:

a.reduce( (res, v, i) => i === a.length - 2 ? res + v + ' and ' : res + v + ( i == a.length -1? '' : ', '), '' )

Он основан на добавлении запятых в конце - за исключением второго последнего (a.length - 2) и способа избежать последней запятой (a.length - 2).

ОБЯЗАТЕЛЬНО должен быть лучший, аккуратный, более разумный способ сделать это?

Это сложная тема для поиска в поисковых системах, потому что она содержит слово "и"...

Ответы

Ответ 1

Один из вариантов будут pop последний элемент, а затем join все остальные запятыми, и сцепить с and плюс последним пунктом:

const input = ['one', 'two', 'three', 'four'];
const last = input.pop();
const result = input.join(', ') + ' and ' + last;
console.log(result);

Ответ 2

Мне нравится подход Марка Мейера (и я бы поддержал его, если бы у меня был представитель), поскольку он не меняет входные данные. Вот мое вращение:

function makeCommaSeparatedString(arr, useOxfordComma) {
    const listStart = arr.slice(0, -1).join(', ');
    const listEnd = arr.slice(-1);
    const conjunction = arr.length <= 1 ? '' :
        useOxfordComma && arr.length > 2 ? ', and ' : ' and ';

    return [listStart, listEnd].join(conjunction);
}

console.log(makeCommaSeparatedString(['one', 'two', 'three', 'four']));
// one, two, three and four
console.log(makeCommaSeparatedString(['one', 'two', 'three', 'four'], true));
// one, two, three, and four
console.log(makeCommaSeparatedString(['one', 'two'], true));
// one and two
console.log(makeCommaSeparatedString(['one']));
// one
console.log(makeCommaSeparatedString([]));
// 

Ответ 3

Вы можете использовать Array.prototype.slice(), когда array.length больше 1, и исключить остальные случаи:

const result = a => a.length > 1 
  ? '${a.slice(0, -1).join(', ')} and ${a.slice(-1)}' 
  : {0: '', 1: a[0]}[a.length];

Пример кода:

const input1 = ['one', 'two', 'three', 'four'];
const input2 = ['A Tale of Two Cities', 'Harry Potter and the smth', 'One Fish, Two Fish, Red Fish, Blue Fish'];
const input3 = ['one', 'two'];
const input4 = ['one'];
const input5 = [];

const result = a => a.length > 1 
  ? '${a.slice(0, -1).join(', ')} and ${a.slice(-1)}' 
  : {0: '', 1: a[0]}[a.length];

console.log(result(input1));
console.log(result(input2));
console.log(result(input3));
console.log(result(input4));
console.log(result(input5));

Ответ 4

Начиная с V8 v7.2 и Chrome 72, вы можете использовать приятный API Intl.ListFormat. Он также позаботится о локализации вашего списка по запросу, что может быть очень полезно, если вам это нужно.

const lf = new Intl.ListFormat('en');

console.log(lf.format(['Frank']));
// → 'Frank'

console.log(lf.format(['Frank', 'Christine']));
// → 'Frank and Christine'

console.log(lf.format(['Frank', 'Christine', 'Flora']));
// → 'Frank, Christine, and Flora'

console.log(lf.format(['Frank', 'Christine', 'Flora', 'Harrison']));
// → 'Frank, Christine, Flora, and Harrison'

// You can use it with other locales
const frlf = new Intl.ListFormat('fr');

console.log(frlf.format(['Frank', 'Christine', 'Flora', 'Harrison']));
// → 'Frank, Christine, Flora et Harrison'

Ответ 5

Другим подходом может быть использование метода splice для удаления двух последних элементов массива и объединения их с помощью токена and. После этого, вы можете нажать этот результат снова на массиве, и, наконец, объединить все элементы, используя , разделитель.


Обновлено:

1) Покажите, как это работает для нескольких случаев (не требуется никакого дополнительного контроля над длиной массива).

2) Оберните логику внутри метода.

3) Не изменяйте исходный массив (если не требуется).

let arrayToCustomStr = (arr, enableMutate) =>
{
    // Clone the received array (if required).
    let a = enableMutate ? arr : arr.slice(0);

    // Convert the array to custom string.
    let removed = a.splice(-2, 2);
    a.push(removed.join(" and "));
    return a.join(", ");
}

// First example, mutate of original array is disabled.
let input1 = ['one', 'two', 'three', 'four'];
console.log("Result for input1:" , arrayToCustomStr(input1));
console.log("Original input1:", input1);

// Second example, mutate of original array is enabled.
let input2 = ['one', 'two'];
console.log("Result for input2:", arrayToCustomStr(input2, true));
console.log("Original input2:", input2);

// Third example, lenght of array is 1.
let input3 = ['one'];
console.log("Result for input3:", arrayToCustomStr(input3));

// Fourth example, empty array.
let input4 = [];
console.log("Result for input4:", arrayToCustomStr(input4));

// Plus example.
let bob = [
    "Don't worry about a thing",
    "Cause every little thing",
    "Gonna be all right",
    "Saying, don't worry about a thing..."
];
console.log("Result for bob:", arrayToCustomStr(bob));
.as-console-wrapper {
    top: 0px;
    max-height: 100% !important;
}

Ответ 6

Используя Array # lower:

['one', 'two', 'three', 'four'].reduce( (a, b, i, array) => a + (i < array.length - 1? ', ': ' and ') + b)

Ответ 7

В основном так же, как один из ответов pop() выше, но вариант, если вы не хотите изменять исходный массив:

let arr = ['one', 'two', 'three', 'four'] 

let s = arr.slice(0,-1).join(', ') + " and " + arr.slice(-1)

console.log(s)

Ответ 8

Intl.ListFormat - это именно то, что вы хотите. Несмотря на то, что в мае 2019 года поддерживаются только Chrome 72+ и Opera 60+, для других браузеров доступен полифилл: https://github.com/zbraniecki/IntlListFormat

const list = ['A', 'B', 'C', 'D'];

// With Oxford comma 
const lfOxfordComma = new Intl.ListFormat('en', {
  style: 'long',
  type: 'conjunction'
});
console.log(lfOxfordComma.format(list)); // → A, B, C, and D


// Without Oxford comma 
const lfComma = new Intl.ListFormat('en-GB', {
  style: 'long',
  type: 'conjunction'
});
console.log(lfComma.format(list)); // → A, B, C and D