2 json сохранить измененные и отсутствующие данные в новый json файл
Содержимое test.json
{
"data": {
"accountid": [{
"series": {
"smart1": 5,
"smart2": 17,
"smart3": 0,
"smart4": 1
}
}, {
"series": {
"smart1": 5,
"smart2": 25,
"smart3": 5,
"smart4": 1
}
}]
}
}
Содержимое test1.json
{
"data": {
"accountid": [{
"series": {
"smart1": 5,
"smart2": 22,
"smart3": 0,
"smart4": 45
}
}, {
"series": {
"smart1": 8,
"smart2": 49,
"smart3": 5,
"smart4": 1,
"smart5": 43
}
}]
}
}
Скрипт, который проверяет 2 файла json и если находит изменение, выводит на экран.
$json1 = file_get_contents('test.json');
$json2 = file_get_contents('test1.json');
$a = json_decode($json1, true);
$b = json_decode($json2, true);
function doublejson($a, $b, $strkey)
{
foreach ($a as $key => $value)
{
foreach ($b as $key2 => $value2)
{
if($key==$key2)
{
if(gettype($value) != "array")
{
if($value2!=$value)
{
$c.="<br>".$strkey.'"'.$key.'"'.":".'"'.$value.'"'." => ".$strkey.'"'.$key2.'"'.":".'"'.$value2.'"'."<br>";
break;
}
else
{
break;
}
}
else
{
$c.=doublejson($a[$key], $b[$key], $strkey.'"'.$key.'":');
break;
}
}
}
}
return $c;
}
echo "<pre>".doublejson($a, $b, "")."</pre>";
Выводит следующее: только изменившиеся значения
"data":"accountid":"0":"series":"smart2":"17" => "data":"accountid":"0":"series":"smart2":"22"
"data":"accountid":"0":"series":"smart4":"1" => "data":"accountid":"0":"series":"smart4":"45"
"data":"accountid":"1":"series":"smart1":"5" => "data":"accountid":"1":"series":"smart1":"8"
"data":"accountid":"1":"series":"smart2":"25" => "data":"accountid":"1":"series":"smart2":"49"
Вопрос1: Как мне сохранить только изменившиеся данные с учетом вычитания value2-value1, должен сохранить в новый файл json такую структуру:
{
"data": {
"accountid": [{
"series": {
"smart2": 5, // 22-17
"smart4": 44 // 45-1
}
}, {
"series": {
"smart1": 3, // 8-5
"smart2": 24 // 49-25
}
}]
}
}
Вопрос2: Какой код нужно дописать, чтобы сохранялось ключ-значение из второго json, которого нет в первом, должно получиться так:
{
"data": {
"accountid": [{
"series": {
"smart2": 5, // 22-17
"smart4": 44 // 45-1
}
}, {
"series": {
"smart1": 3, // 8-5
"smart2": 24, // 49-25
"smart5": 43 // этот ключ-значение отсутствует в первом json и должен сохраниться в новом файле json
}
}]
}
}
Ответы (2 шт):
Допустим ключи второго массива соответствуют первому, плюс могут быть новые.
- Для удобства извлечем данные, которые непосредственно надо сравнивать (то есть сами массивы сравнения).
- Берем попарно два таких массива
$a, $b. - Идем по массиву
$b. - Если ключ в массиве
$aотсутствует, то пропускаем. - Если есть, то сравниваем значения. Если изменилось, вычитаем
- Если не изменилось, удаляем из массива.
- возвращаем результат с ключом
series
-
function diff($a, $b){
$a = array_column($a['data']['accountid'], 'series'); // 1
$b = array_column($b['data']['accountid'], 'series');
$result = array_map(function($a, $b){ // 2
foreach($b as $k => &$v){ // 3
if(!isset($a[$k])) continue; // 4
if($a[$k] != $v) $v -= $a[$k]; // 5
else unset($b[$k]); // 6
}
return ['series' => $b]; // 7
}, $a, $b);
return ['data' => ['accountid' => $result]];
}
Понимаю, что это не совсем относится к задаче, но это нужно переписать, чтобы получить более аккуратный и читаемый код
Возможно я просто не совсем понимаю задачу, но это можно сделать одним циклом с рекурсией. Для задачи нам нужно взять взять массив, на который мы будем опираться. В нашем случае это второй ($two)
В начале каждой итерации необходимо проверить существование элемента в первом массиве: isset($one[$key])
Далее получить значение и проверить его тип. Вместо gettype($val) == 'array' можно использовать функцию is_array, которая вернет bool. То что нам сейчас нужно. Так как сама функиция ожидает на вход два массива, мы и будем проверять сразу два значения, являются ли они массивами. Это нужно, чтобы избежать неожиданных последствий в виде внезапного Warning
Это решение делает то же самое, что и решение @teran, но является более универсальным (хотя можно использовать только его функцию array_map с аргументами и получится почти то же самое):
function findDoubleAndUnique($one, $two) {
$double = [];
foreach($two as $key => $val) {
if(!isset($one[$key])) {
$double[$key] = $val;
continue;
}
$val2 = $one[$key];
if(is_array($val) && is_array($val2)) {
$double[$key] = findDoubleAndUnique($val2, $val);
} else if ($val != $val2) {
$double[$key] = $val - $val2;
}
}
return $double;
}
Ну и использование:
$json1 = json_decode(file_get_contents('1.json'), true);
$json2 = json_decode(file_get_contents('2.json'), true);
file_put_contents('out.json', json_encode(findDoubleAndUnique($json1, $json2), JSON_PRETTY_PRINT));