У меня есть «доступные» данные и я хочу преобразовать их в «желаемые».
Я пытался объединить все объекты внутри массива, используя это, но это не работает, потому что, как вы можете видеть, для timestamp = 10 у нас есть 2 значения sw_version.
const available = [
{
"timestamp": 10,
"sw_version": "AA"
},
{
"timestamp": 10,
"sw_version": "AB"
},
{
"timestamp": 20,
"sw_version": "QFX-1.2.5 B"
},
{
"timestamp": 10,
"pressure": 14.75
},
{
"timestamp": 20,
"pressure": 14.22
},
{
"timestamp": 10,
"temperature": 15.96
},
{
"timestamp": 20,
"temperature": 38.50
},
{
"timestamp": 30,
"temperature": 2.2
},
{
"timestamp": 30,
"pressure": 9.8
}
]
const desired = [
{
"timestamp": 10,
"sw_version": "AA",
"pressure": 14.75,
"temperature": 15.96
},
{
"timestamp": 10,
"sw_version": "AB",
"pressure": 14.75,
"temperature": 15.96
},
{
"timestamp": 20,
"sw_version": "QFX-1.2.5 B",
"pressure": 14.22,
"temperature": 38.5
},
{
"timestamp": 30,
"pressure": 9.8,
"temperature": 2.2
}
]
const output = available.reduce((result, item) => {
const i = result.findIndex((resultItem) => resultItem.timestamp === item.timestamp);
if (i === -1) {
result.push(item);
} else {
result[i] = { ...result[i], ...item };
}
return result;
}, []);
console.info(output)
Результат был
[
{
"timestamp": 10,
"sw_version": "AB",
"pressure": 14.75,
"temperature": 15.96
},
{
"timestamp": 20,
"sw_version": "QFX-1.2.5 B",
"pressure": 14.22,
"temperature": 38.5
},
{
"timestamp": 30,
"temperature": 2.2,
"pressure": 9.8
}
]
Как вы можете видеть в желаемом выводе, мне нужны 2 объекта с меткой времени = 10, но в выводе функции он перезаписывает первый и сохраняет только один объект.
Мы получим несколько значений для одной и той же отметки времени только для одного измерения — sw_version. Для других измерений, таких как температура или давление, мы не получим несколько значений для одних и тех же временных меток. sw_version также является необязательным, поэтому мы можем получить данные, в которых sw_version не будет, и нам просто нужно объединить, не думая о дублировании строк. временная метка обязательна, она всегда будет там
пожалуйста, уточните свой вопрос: строки с sw_version
всегда являются первыми в исходном массиве?
Уточните, пожалуйста, ваш вопрос: есть ли финальная строка без свойств timestamp
или sw_version
?
@Mushroomator, чтобы ответить на ваш первый вопрос: да, мы можем получить второе значение давления или температуры для метки времени, где у нас уже есть измерение, такое же, как sw_version. Ответ на второй вопрос: нет, одно и то же измерение для одной и той же метки времени дважды не произойдет. Надеюсь, это ответит на ваш вопрос, и спасибо, что спросили.
@MisterJojo Ответ на оба ваших вопроса: нет. sw_version может появиться где угодно. и ни одна строка без отметки времени невозможна. Спасибо
Есть еще одна проблема. Учитывая ваши данные, предположим, вы получили еще одно измерение { timestamp: 10, temperature: 420 }
. Сколько выходных объектов вы ожидаете для отметки времени 10 или какие здесь должны быть значения для версии программного обеспечения? AA
или AB
или иметь два объекта для обоих? Проблема здесь будет в том, что чем больше измерений вы получите, тем больше возможных комбинаций значений. На мой взгляд, у вас есть концептуальная проблема со стратегией слияния. Я мог бы представить что-то вроде этого { timestamp: 10, temp: [20, 10], sw_version: ["AA", "BB"] }
для работы, но, очевидно, не знаю варианта использования.
@Mushroomator То, на что вы указываете, - очень правильная ситуация, поэтому на данный момент мы можем предположить, что только одно свойство, такое как sw_version, может иметь более 1 значений для одной и той же метки времени. я тоже отредактирую вопрос
это можно было бы сделать так:
const available =
[ { timestamp: 10, sw_version: 'AA' }
, { timestamp: 10, sw_version: 'AB' }
, { timestamp: 10, pressure: 14.75 }
, { timestamp: 20, pressure: 14.22 }
, { timestamp: 10, temperature: 15.96 }
, { timestamp: 20, temperature: 38.50 }
, { timestamp: 20, sw_version: 'QFX-1.2.5 B' } // off order
, { timestamp: 30, temperature: 2.2 }
, { timestamp: 30, pressure: 9.8 }
];
const result = available
.filter( ({ sw_version }) => !sw_version )
.reduce( (res, { timestamp, ...props }) =>
{
let rows = res.filter( elm => elm.timestamp === timestamp );
if (!rows.length )
res.push({timestamp,...props});
else
rows.forEach( line => Object.assign(line, props));
return res;
}
, available
.filter( ({ timestamp:t, sw_version:v }) => !!t && !!v )
.map( x => Object.assign({},x))
);
console.info( JSON.stringify(result,0,2))
.as-console-wrapper { max-height: 100% !important; top: 0; }
это не удается, если sw_version отсутствует, например [{ "timestamp": 20, "pressure": 14.22 } { "timestamp": 20, "temperature": 38.50 } ]
@Shaick: Я спросил тебя об этом is there some final line without timestamp or sw_version properties
и ты ответил no
Почему ты меняешь это правило?
Извините, меня смутило слово «финал». Вот почему я сказал «Нет». Я прошу прощения за это. Таким образом, Timestamp всегда будет присутствовать, но sw_version не является обязательным.
Последняя строка @samikh означает любые строки в вашем массиве desired
. и все они имеют свойства timestamp
и sw_version
. Если это не так, вам следует отредактировать свой вопрос, указав действительно репрезентативный случай для входных и выходных массивов, что на самом деле не так.
@samikh Я обновил свой ответ.
Во-первых, я бы сгруппировал timestamp
и сохранил все sw_version
в массиве. Затем я бы создал ожидаемую структуру для каждого sw_version
для каждого timestamp
. Я бы использовал особый случай, если нет sw_version
.
const available = [{"timestamp": 10,"sw_version": "AA"},{"timestamp": 10,"sw_version": "AB"},{"timestamp": 20,"sw_version": "QFX-1.2.5 B"},{"timestamp": 10,"pressure": 14.75},{"timestamp": 20,"pressure": 14.22},{"timestamp": 10,"temperature": 15.96},{"timestamp": 20,"temperature": 38.50},{"timestamp": 30,"temperature": 2.2},{"timestamp": 30,"pressure": 9.8}];
const output = Object.entries(available.reduce((acc, el) => {
if (!(el.timestamp in acc)) acc[el.timestamp] = {};
if ("sw_version" in el)
if (!("sw_version" in acc[el.timestamp])) acc[el.timestamp].sw_version = [el.sw_version];
else acc[el.timestamp].sw_version.push(el.sw_version);
else
acc[el.timestamp] = {...acc[el.timestamp], ...el};
return acc;
}, {})).flatMap(([timestamp, el]) => !("sw_version" in el)
? el
: el.sw_version.map(sw_version => ({
...el,
sw_version
}))
);
console.info(output);
Я думаю, вам нужно предоставить больше правил относительно того, как именно здесь происходит слияние. Например. что происходит, когда вы получаете второе значение для
pressure
илиtemperature
для отметки времени, для которой у вас уже есть измерение? Хотите ли вы поступить с этим так же, как и сsw_version
i. е. также есть отдельный объект на выходе для них? Что произойдет, если вы получите одно и то же измерение для одной и той же временной метки дважды, например.m1 = { timestamp: 10, temp: 10 }
иm2 = { timestamp: 10, temp: 10 }
. Должны ли это быть один или два объекта на выходе?