Предупреждающее сообщение верное. Вы возвращаете адрес локального массива, который исчезает после возвращения функции.
Вы можете сделать это, используя распределение динамической памяти:
char *recvmsg(){
char *buffer = (char*)malloc(1024);
return buffer;
}
Уловка заключается в том, что вам нужно убедитесь, что вы free()
указатель позже, чтобы избежать утечки памяти.
В качестве альтернативы вы можете передать буфер в функцию.
void recvmsg(char *buffer,int buffer_size){
// write to buffer
}
void main(){
char buffer[1024];
recvmsg(buffer,1024);
}
Это позволяет избежать необходимости выделение памяти. Это действительно предпочтительный способ сделать это.
Я написал небольшой класс, который делает то, что вы хотите, вы можете проверить его здесь .
Единственное, что отличается от вашего предложения, это то, что я не считаю [1,[{c: 1},2,3],{a:'hey'}] and [{a:'hey'},1,[3,{c: 1},2]]
будет таким же, потому что я думаю, что массивы не равны, если порядок их элементов не одинаковый. Конечно, это может быть изменено, если необходимо. Кроме того, этот код может быть дополнительно расширен, чтобы использовать функцию в качестве аргумента, которая будет использоваться для форматирования объекта diff произвольным образом на основе переданных примитивных значений (теперь это задание выполняется методом «compareValues»).
var deepDiffMapper = function() {
return {
VALUE_CREATED: 'created',
VALUE_UPDATED: 'updated',
VALUE_DELETED: 'deleted',
VALUE_UNCHANGED: 'unchanged',
map: function(obj1, obj2) {
if (this.isFunction(obj1) || this.isFunction(obj2)) {
throw 'Invalid argument. Function given, object expected.';
}
if (this.isValue(obj1) || this.isValue(obj2)) {
return {
type: this.compareValues(obj1, obj2),
data: (obj1 === undefined) ? obj2 : obj1
};
}
var diff = {};
for (var key in obj1) {
if (this.isFunction(obj1[key])) {
continue;
}
var value2 = undefined;
if ('undefined' != typeof(obj2[key])) {
value2 = obj2[key];
}
diff[key] = this.map(obj1[key], value2);
}
for (var key in obj2) {
if (this.isFunction(obj2[key]) || ('undefined' != typeof(diff[key]))) {
continue;
}
diff[key] = this.map(undefined, obj2[key]);
}
return diff;
},
compareValues: function(value1, value2) {
if (value1 === value2) {
return this.VALUE_UNCHANGED;
}
if (this.isDate(value1) && this.isDate(value2) && value1.getTime() === value2.getTime()) {
return this.VALUE_UNCHANGED;
}
if ('undefined' == typeof(value1)) {
return this.VALUE_CREATED;
}
if ('undefined' == typeof(value2)) {
return this.VALUE_DELETED;
}
return this.VALUE_UPDATED;
},
isFunction: function(obj) {
return {}.toString.apply(obj) === '[object Function]';
},
isArray: function(obj) {
return {}.toString.apply(obj) === '[object Array]';
},
isDate: function(obj) {
return {}.toString.apply(obj) === '[object Date]';
},
isObject: function(obj) {
return {}.toString.apply(obj) === '[object Object]';
},
isValue: function(obj) {
return !this.isObject(obj) && !this.isArray(obj);
}
}
}();
var result = deepDiffMapper.map({
a:'i am unchanged',
b:'i am deleted',
e:{ a: 1,b:false, c: null},
f: [1,{a: 'same',b:[{a:'same'},{d: 'delete'}]}],
g: new Date('2017.11.25')
},
{
a:'i am unchanged',
c:'i am created',
e:{ a: '1', b: '', d:'created'},
f: [{a: 'same',b:[{a:'same'},{c: 'create'}]},1],
g: new Date('2017.11.25')
});
console.log(result);
Я знаю, что опаздываю на вечеринку, но мне нужно было что-то подобное, что вышеприведенные ответы не помогли.
Я использовал функцию часовых часов Angular для обнаружения изменений в переменной. Мне не только нужно было знать, изменилось ли свойство в переменной, но я также хотел убедиться, что измененное свойство не было временным, рассчитанным полем. Другими словами, я хотел игнорировать некоторые свойства.
Вот код: https://jsfiddle.net/rv01x6jo/
Вот как использовать it:
// To only return the difference
var difference = diff(newValue, oldValue);
// To exclude certain properties
var difference = diff(newValue, oldValue, [newValue.prop1, newValue.prop2, newValue.prop3]);
Надеюсь, это кому-то поможет.
Я использовал этот фрагмент кода для выполнения описанной вами задачи:
function mergeRecursive(obj1, obj2) {
for (var p in obj2) {
try {
if(obj2[p].constructor == Object) {
obj1[p] = mergeRecursive(obj1[p], obj2[p]);
}
// Property in destination object set; update its value.
else if (Ext.isArray(obj2[p])) {
// obj1[p] = [];
if (obj2[p].length < 1) {
obj1[p] = obj2[p];
}
else {
obj1[p] = mergeRecursive(obj1[p], obj2[p]);
}
}else{
obj1[p] = obj2[p];
}
} catch (e) {
// Property in destination object not set; create it and set its value.
obj1[p] = obj2[p];
}
}
return obj1;
}
это даст вам новый объект, который объединит все изменения между старым объектом и новым объектом из ваша форма
$.extend(true,obj1,obj2)
с помощью jQuery. Это совсем не то, что мне нужно. Мне нужна разница между двумя объектами, а не их комбинацией.
– Martin Jespersen
21 December 2011 в 20:03
Вот библиотека JavaScript, которую вы можете использовать для поиска diff между двумя объектами JavaScript:
Github url: https://github.com/cosmicanant/recursive-diff
Npmjs url: https://www.npmjs.com/package/recursive-diff
[/g2]
Вы можете использовать библиотеку recursive-diff в браузере, а также Node.js. Для браузера выполните следующие действия:
<script type="text" src="index.js"/>
<script type="text/javascript">
var ob1 = {a:1, b: [2,3]};
var ob2 = {a:2, b: [3,3,1]};
var delta = diff.getDiff(ob1,ob2);
/* console.log(delta) will dump following data
{
'/a':{operation:'update',value:2}
'/b/0':{operation:'update',value:3},
'/b/2':{operation:'add',value:1},
} */
var ob3 = diff.applyDiff(ob1, delta); //expect ob3 is deep equal to ob2
</script>
Если в node.js вам может потребоваться модуль «рекурсивный-diff» и использовать его, как показано ниже:
var diff = require('recursive-diff');
var ob1 = {a: 1}, ob2: {b:2};
var diff = diff.getDiff(ob1, ob2);
В наши дни для этого доступно немало модулей. Недавно я написал модуль для этого, потому что меня не устраивало множество различных модулей, которые я нашел. Его называют odiff
: https://github.com/Tixit/odiff . Я также перечислил кучу самых популярных модулей и почему они не были приемлемы в readme из odiff
, которые вы могли бы просмотреть, если odiff
не обладает требуемыми свойствами. Вот пример:
var a = [{a:1,b:2,c:3}, {x:1,y: 2, z:3}, {w:9,q:8,r:7}]
var b = [{a:1,b:2,c:3},{t:4,y:5,u:6},{x:1,y:'3',z:3},{t:9,y:9,u:9},{w:9,q:8,r:7}]
var diffs = odiff(a,b)
/* diffs now contains:
[{type: 'add', path:[], index: 2, vals: [{t:9,y:9,u:9}]},
{type: 'set', path:[1,'y'], val: '3'},
{type: 'add', path:[], index: 1, vals: [{t:4,y:5,u:6}]}
]
*/
Использование Underscore, простой diff:
var o1 = {a: 1, b: 2, c: 2},
o2 = {a: 2, b: 1, c: 2};
_.omit(o1, function(v,k) { return o2[k] === v; })
Результаты в частях o1
, которые соответствуют, но с разными значениями в o2
:
{a: 1, b: 2}
It 'd различны для глубокого diff:
function diff(a,b) {
var r = {};
_.each(a, function(v,k) {
if(b[k] === v) return;
// but what if it returns an empty object? still attach?
r[k] = _.isObject(v)
? _.diff(v, b[k])
: v
;
});
return r;
}
Как указано в комментариях @Juhana, вышесказанное является только разложением a -> b, а не обратимым (что означает, что дополнительные свойства в b будут игнорироваться). Вместо этого используйте a -> b -> a:
(function(_) {
function deepDiff(a, b, r) {
_.each(a, function(v, k) {
// already checked this or equal...
if (r.hasOwnProperty(k) || b[k] === v) return;
// but what if it returns an empty object? still attach?
r[k] = _.isObject(v) ? _.diff(v, b[k]) : v;
});
}
/* the function */
_.mixin({
diff: function(a, b) {
var r = {};
deepDiff(a, b, r);
deepDiff(b, a, r);
return r;
}
});
})(_.noConflict());
См. http://jsfiddle.net/drzaus/9g5qoxwj/ для полного примера + тесты + mixins
omit
будет глубоким различием, но был неправильным, поэтому включен и для сравнения.
– drzaus
3 November 2014 в 20:33
r[k] = ... : v
в r[k] = ... : {'a':v, 'b':b[k] }
, таким образом вы можете увидеть два значения.
– guyaloni
3 February 2015 в 18:59
{a:1, b:2}
и {a:1, b:2, c:3}
.
– JJJ
19 January 2016 в 21:53
Я просто использую ramda, для решения той же проблемы, мне нужно знать, что изменилось в новом объекте. Итак, вот мой дизайн.
const oldState = {id:'170',name:'Ivab',secondName:'Ivanov',weight:45};
const newState = {id:'170',name:'Ivanko',secondName:'Ivanov',age:29};
const keysObj1 = R.keys(newState)
const filterFunc = key => {
const value = R.eqProps(key,oldState,newState)
return {[key]:value}
}
const result = R.map(filterFunc, keysObj1)
Результат - имя свойства и его статус.
[{"id":true}, {"name":false}, {"secondName":true}, {"age":false}]
Я разработал функцию с именем «compareValue ()» в Javascript. он возвращает, является ли значение одинаковым или нет. Я вызвал compareValue () для цикла одного объекта. вы можете получить различие двух объектов в diffParams.
var diffParams = {};
var obj1 = {"a":"1", "b":"2", "c":[{"key":"3"}]},
obj2 = {"a":"1", "b":"66", "c":[{"key":"55"}]};
for( var p in obj1 ){
if ( !compareValue(obj1[p], obj2[p]) ){
diffParams[p] = obj1[p];
}
}
function compareValue(val1, val2){
var isSame = true;
for ( var p in val1 ) {
if (typeof(val1[p]) === "object"){
var objectValue1 = val1[p],
objectValue2 = val2[p];
for( var value in objectValue1 ){
isSame = compareValue(objectValue1[value], objectValue2[value]);
if( isSame === false ){
return false;
}
}
}else{
if(val1 !== val2){
isSame = false;
}
}
}
return isSame;
}
console.log(diffParams);
Я уже написал функцию для одного из моих проектов, который будет сравнивать объект как пользовательские параметры с его внутренним клоном. Он также может проверять и даже заменять значения по умолчанию, если пользователь вводил плохой тип данных или удалялся в чистом javascript.
В IE8 работает 100%. Протестировано успешно.
// ObjectKey: ["DataType, DefaultValue"]
reference = {
a : ["string", 'Defaul value for "a"'],
b : ["number", 300],
c : ["boolean", true],
d : {
da : ["boolean", true],
db : ["string", 'Defaul value for "db"'],
dc : {
dca : ["number", 200],
dcb : ["string", 'Default value for "dcb"'],
dcc : ["number", 500],
dcd : ["boolean", true]
},
dce : ["string", 'Default value for "dce"'],
},
e : ["number", 200],
f : ["boolean", 0],
g : ["", 'This is an internal extra parameter']
};
userOptions = {
a : 999, //Only string allowed
//b : ["number", 400], //User missed this parameter
c: "Hi", //Only lower case or case insitive in quotes true/false allowed.
d : {
da : false,
db : "HelloWorld",
dc : {
dca : 10,
dcb : "My String", //Space is not allowed for ID attr
dcc: "3thString", //Should not start with numbers
dcd : false
},
dce: "ANOTHER STRING",
},
e: 40,
f: true,
};
function compare(ref, obj) {
var validation = {
number: function (defaultValue, userValue) {
if(/^[0-9]+$/.test(userValue))
return userValue;
else return defaultValue;
},
string: function (defaultValue, userValue) {
if(/^[a-z][a-z0-9-_.:]{1,51}[^-_.:]$/i.test(userValue)) //This Regex is validating HTML tag "ID" attributes
return userValue;
else return defaultValue;
},
boolean: function (defaultValue, userValue) {
if (typeof userValue === 'boolean')
return userValue;
else return defaultValue;
}
};
for (var key in ref)
if (obj[key] && obj[key].constructor && obj[key].constructor === Object)
ref[key] = compare(ref[key], obj[key]);
else if(obj.hasOwnProperty(key))
ref[key] = validation[ref[key][0]](ref[key][1], obj[key]); //or without validation on user enties => ref[key] = obj[key]
else ref[key] = ref[key][1];
return ref;
}
//console.log(
alert(JSON.stringify( compare(reference, userOptions),null,2 ))
//);
/ * result
{
"a": "Defaul value for \"a\"",
"b": 300,
"c": true,
"d": {
"da": false,
"db": "Defaul value for \"db\"",
"dc": {
"dca": 10,
"dcb": "Default value for \"dcb\"",
"dcc": 500,
"dcd": false
},
"dce": "Default value for \"dce\""
},
"e": 40,
"f": true,
"g": "This is an internal extra parameter"
}
*/
Я хотел бы предложить решение ES6 ... Это односторонний diff, что означает, что он вернет ключи / значения из o2
, которые не идентичны их аналогам в o1
:
let o1 = {
one: 1,
two: 2,
three: 3
}
let o2 = {
two: 2,
three: 3,
four: 4
}
let diff = Object.keys(o2).reduce((diff, key) => {
if (o1[key] === o2[key]) return diff
return {
...diff,
[key]: o2[key]
}
}, {})
let
- ES6, а оператор расширения объекта ...
- это будущее ES, поэтому вам нужно запустить его в среде, которая их поддерживает.
– senornestor
12 May 2017 в 19:25
с использованием lodash.
function difference(object, base) {
function changes(object, base) {
return _.transform(object, function(result, value, key) {
if (!_.isEqual(value, base[key])) {
result[key] = (_.isObject(value) && _.isObject(base[key])) ? changes(value, base[key]) : value;
}
});
}
return changes(object, base);
}
Более расширенная и упрощенная функция из ответа sbgoran. Это позволяет осуществлять глубокое сканирование и находить симлимутность массива.
var result = objectDifference({
a:'i am unchanged',
b:'i am deleted',
e: {a: 1,b:false, c: null},
f: [1,{a: 'same',b:[{a:'same'},{d: 'delete'}]}],
g: new Date('2017.11.25'),
h: [1,2,3,4,5]
},
{
a:'i am unchanged',
c:'i am created',
e: {a: '1', b: '', d:'created'},
f: [{a: 'same',b:[{a:'same'},{c: 'create'}]},1],
g: new Date('2017.11.25'),
h: [4,5,6,7,8]
});
console.log(result);
function objectDifference(obj1, obj2){
if((dataType(obj1) !== 'array' && dataType(obj1) !== 'object') || (dataType(obj2) !== 'array' && dataType(obj2) !== 'object')){
var type = '';
if(obj1 === obj2 || (dataType(obj1) === 'date' && dataType(obj2) === 'date' && obj1.getTime() === obj2.getTime()))
type = 'unchanged';
else if(dataType(obj1) === 'undefined')
type = 'created';
if(dataType(obj2) === 'undefined')
type = 'deleted';
else if(type === '') type = 'updated';
return {
type: type,
data:(obj1 === undefined) ? obj2 : obj1
};
}
if(dataType(obj1) === 'array' && dataType(obj2) === 'array'){
var diff = [];
obj1.sort(); obj2.sort();
for(var i = 0; i < obj2.length; i++){
var type = obj1.indexOf(obj2[i]) === -1?'created':'unchanged';
if(type === 'created' && (dataType(obj2[i]) === 'array' || dataType(obj2[i]) === 'object')){
diff.push(
objectDifference(obj1[i], obj2[i])
);
continue;
}
diff.push({
type: type,
data: obj2[i]
});
}
for(var i = 0; i < obj1.length; i++){
if(obj2.indexOf(obj1[i]) !== -1 || dataType(obj1[i]) === 'array' || dataType(obj1[i]) === 'object')
continue;
diff.push({
type: 'deleted',
data: obj1[i]
});
}
} else {
var diff = {};
var key = Object.keys(obj1);
for(var i = 0; i < key.length; i++){
var value2 = undefined;
if(dataType(obj2[key[i]]) !== 'undefined')
value2 = obj2[key[i]];
diff[key[i]] = objectDifference(obj1[key[i]], value2);
}
var key = Object.keys(obj2);
for(var i = 0; i < key.length; i++){
if(dataType(diff[key[i]]) !== 'undefined')
continue;
diff[key[i]] = objectDifference(undefined, obj2[key[i]]);
}
}
return diff;
}
function dataType(data){
if(data === undefined || data === null) return 'undefined';
if(data.constructor === String) return 'string';
if(data.constructor === Array) return 'array';
if(data.constructor === Object) return 'object';
if(data.constructor === Number) return 'number';
if(data.constructor === Boolean) return 'boolean';
if(data.constructor === Function) return 'function';
if(data.constructor === Date) return 'date';
if(data.constructor === RegExp) return 'regex';
return 'unknown';
}
Использование Lodash:
_.mergeWith(oldObj, newObj, function (objectValue, sourceValue, key, object, source) {
if ( !(_.isEqual(objectValue, sourceValue)) && (Object(objectValue) !== objectValue)) {
console.log(key + "\n Expected: " + sourceValue + "\n Actual: " + objectValue);
}
});
Я не использую ключ / объект / источник, но я оставил его там, если вам нужно доступ к ним. Сравнение объектов просто препятствует консоли печатать различия с консолью от внешнего элемента до самого внутреннего элемента.
Вы можете добавить некоторую логику внутри для обработки массивов. Возможно, сначала отсортируйте массивы. Это очень гибкое решение.
Изменено с _.merge на _.mergeWith из-за обновления lodash. Спасибо Aviron за то, что заметили изменения.
c
создается какundefined
, но должен быть строкой'i am created'
), и, кроме того, делать то, что мне нужно, так как ему не хватает глубокого сравнения значений массива, который является наиболее важной (и сложной / сложной) частью. В качестве побочной заметки конструкция'array' != typeof(obj)
бесполезна, поскольку массивы являются объектами, которые являются экземплярами массивов. – Martin Jespersen 21 December 2011 в 23:43{type: ..., data:..}
. То, что отсутствует, - это поиск значения из первого массива во втором, но, как я упоминал в своем ответе, я не думаю, что массивы равны, если порядок их значений не равен ([1, 2, 3] is not equal to [3, 2, 1]
, на мой взгляд). – sbgoran 22 December 2011 в 00:32[{key: 'value1'}] and [{key: 'value2'}, {key: 'value3'}]
. Теперь первый объект в первом массиве, обновленный с «значением1», или "значение2". И это простой пример, он может усложниться с глубоким вложением. Если вы хотите / нуждаетесь в глубоком сопоставлении вложенности, независимо от положения ключа, не создавайте массивы объектов, создавайте объекты с вложенными объектами, как в предыдущем примере:{inner: {key: 'value1'}} and {inner: {key: 'value2'}, otherInner: {key: 'value3'}}
. – sbgoran 22 December 2011 в 10:27