Фильтровать или уменьшать массив строк по подстроке

#javascript #arrays #string #filter #split

#javascript #массивы #строка #Фильтр #разделить

Вопрос:

У меня есть массив строк :
let arr = ["cap:1", "col:red", "cap:3", "cap:1", "col:blue", "screen:yes"]
и я хочу иметь новый массив с одним элементом из каждой категории подстрок («cap», «col», «screen»), с наименьшим индексом:
let newArray = ["cap:1","col:red","screen:yes"]
//"cap:1" from newArray is arr[0]
Я пробовал этот способ:

 const newArr = (arr) => {
    let c= []
    let c = [...c, arr[0]]  
    for(let i = 1; i<arr.length; i  ){
        for (let j=0; j<c.length; j  ){
            if(arr[i].split(":")[0] !== c[j].split(":")){
                c = [...c, arr[i]]
            }
        }
    }
    return c  
}
 

но это переходит в бесконечный цикл, и результат выглядит примерно так: ["cap:1","col:red","col:red","col:red","col:red","col:red","col:red","col:red"...
Не могли бы вы мне помочь?
Спасибо!

Ответ №1:

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

 let arr = ["cap:1", "col:red", "cap:3", "cap:1", "col:blue", "screen:yes"];
const newArr = (arr) => {
  let c = [];
  const suffixObj = {};
  for (let i = 0; i < arr.length; i  ) {
    const getPrefix = arr[i].split(":")[0];
    if (!suffixObj.hasOwnProperty(getPrefix)) {
      c.push(arr[i]);
      suffixObj[getPrefix] = true
    }
  }

  return c
};

console.log(newArr(arr)) 

Ответ №2:

Вы могли бы взять a Set с массивом разделенных первых частей.

В результате получаем массив из набора.

 const
    array = ["cap:1", "col:red", "cap:3", "cap:1", "col:blue", "screen:yes"],
    types = [...new Set(array.map(s => s.split(':', 1)[0]))];

console.log(types); 

Ответ №3:

Ваша логика не имеет способа определить, что префикс текущего элемента не был найден newArr . Кроме того, в условии arr[i].split(":")[0] !== c[j].split(":") вы сравниваете строку с массивом, который всегда возвращает true — string !== array .

Возможно, вы намеревались написать arr[i].split(":")[0] !== c[j].split(":")[0] , что все равно не дало бы вам желаемого результата.

Вы можете отказаться от внутреннего цикла и проверить каждый элемент на newArr использование c.every(el => !...) следующим образом:

 let arr = ["cap:1", "col:red", "cap:3", "cap:1", "col:blue", "screen:yes"];

const newArr = (arr) => {
    let c = [arr[0]]; 
    for(let i = 1; i<arr.length; i  ) {
        if( c.every(el => !arr[i].startsWith( el.split(':')[0] )) ) {
            c = [ ...c, arr[i] ];
        }
    }
    return c; 
}

console.log( newArr( arr ) ); 

Ответ №4:

Это отличный вариант использования Array.Reduce . Вы можете уменьшить множество значений вашего массива в компактный объект, разделив записи на ключевые значения и просто взяв первую запись для данного ключа. Что-то подобное должно сработать для вас:

 const firstOfGroup = arr => arr.reduce((result, currentValue) => {
   const parts = currentValue.split(':');
   const key = parts[0];
   const value = parts[1];
   if (!result.hasOwnProperty(key)) {
      result[key] = value;
   }
   return resu<
});
 

Если вам конкретно нужны результаты, помещенные в массив, вы можете повторно собрать части в этот формат, но итерация по результирующему объекту должна быть достаточно эффективной.

Ответ №5:

Вот решение, которое может вам помочь! Сначала вам нужно сопоставить все данные, чтобы получить поток ключ-значение. Затем этот поток можно уменьшить, чтобы сохранить только первое вхождение.

 let newArr = data.map(function(item){
        return item.split(":")
    }).reduce(function(acc, curr){
        if(acc[curr[0]] === undefined){
            acc[curr[0]] = curr[1]
        }
        return acc
    })