I need a solution for the following problem.
I have an array, but there are various types data in it.
Example: [1,2,'string1','string2']
I need a function that does intersection, but for only the matching types.
This is what I mean:
intersect([1,2,'string1','string2'],['string2','string3']) // [1,2,'string2']
intersect([1,2,'string1','string2'],[2,3]) // [2,'string1','string2']
The second argument is always the same type, it is not mixed.
I have this:
function intersect(a, b) {
var t;
if (b.length > a.length) t = b, b = a, a = t; // indexOf to loop over shorter
return a.filter(function (e) {
return b.indexOf(e) > -1;
});
}
but it always removes the other type too :(
function intersect(a, b) {
var t;
if (b.length > a.length) t = b, b = a, a = t; // indexOf to loop over shorter
const type = typeof(b[0]); //check the type of the second array's first element since each element has the same type
const tempArray = a.filter(function (e) {
return typeof(e) !== type;
}); //filter the first array if it has different item types than the second array's elements
return tempArray.concat(a.filter(function (e) {
return b.indexOf(e) > -1;
}));
}
console.log(intersect([1,2,'string1','string2'],['string2','string3'])) // [1,2,'string2']
Related
Case 1
let x =[{_id:"1",name:"abc"},{_id:"2",name:"def"}]
let y=[{_id:"1",name:"abc"},{_id:"3",name:"def"}]
isDifferent(x,y) must return true.
Case 2
let a=[{_id:"1",name:"abc"},{_id:"2",name:"def"}]
let b=[{_id:"2",name:"def"},{_id:"1",name:"abc"}]
isDifferent(a,b) must return false.
Case 3
let p=[{_id:"1",name:"abc"},{_id:"2",name:"def"}]
let q=[{_id:"1",name:"abc"},{_id:"2",name:"def"}]
isDifferent(a,b) must return false.
I tried using isMatch function of lodash
isDifferent(arr1, arr2) {
return !isMatch(arr1, arr2);
}
Case 1 and Case 3 works as expected. But in Case 2, the function returns true. Note that only the order of the objects in the array is interchanged.
I cannot check based on _id since the two arrays that I compare may not have _id at all.
let p=[{name:"abc",age:"2"},{name:"def",age:"2"}]
let q=[{name:"abc",age:"3"},{name:"def",age:"4"}]
The arrays could be like this. But what I can guarantee is the objects will have same properties in both arrays
Use the isEuqual method provided by lodash as it performs a deep comparison between two values to determine if they are equivalent.
_.isEqual(array1, array2);
This method supports comparing arrays, array buffers, booleans, date objects, error objects, maps, numbers, Object objects, regexes, sets, strings, symbols, and typed arrays. Object objects are compared by their own, not inherited, enumerable properties. Functions and DOM nodes are compared by strict equality, i.e. ===.
You can use lodash#xorWith with lodash#isEqual as the comparator function to get an array of items that are different from argument a and b. We can infer that a and b are different based on the length of the resulting array.
function isDifferent(a, b) {
return _.xorWith(a, b, _.isEqual).length > 0;
}
let x =[{_id:"1",name:"abc"},{_id:"2",name:"def"}]
let y=[{_id:"1",name:"abc"},{_id:"3",name:"def"}];
let a=[{_id:"1",name:"abc"},{_id:"2",name:"def"}];
let b=[{_id:"2",name:"def"},{_id:"1",name:"abc"}];
let p=[{_id:"1",name:"abc"},{_id:"2",name:"def"}];
let q=[{_id:"1",name:"abc"},{_id:"2",name:"def"}];
console.log(isDifferent(x, y));
console.log(isDifferent(a, b));
console.log(isDifferent(p, q));
function isDifferent(a, b) {
return _.xorWith(a, b, _.isEqual).length > 0;
}
.as-console-wrapper{min-height:100%;top:0}
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.10/lodash.min.js"></script>
I'll use isEqual() method.
// False
let x =[{_id:"1",name:"abc"},{_id:"2",name:"def"}]
let y= [{_id:"1",name:"abc"},{_id:"3",name:"def"}]
// true
let a=[{_id:"1",name:"abc"},{_id:"2",name:"def"}]
let b=[{_id:"2",name:"def"},{_id:"1",name:"abc"}]
//true
let p=[{_id:"1",name:"abc"},{_id:"2",name:"def"}]
let q=[{_id:"1",name:"abc"},{_id:"2",name:"def"}]
function compare(a, b) {
var key = Object.keys(a)[0];
if (a[key] < b[key])
return -1;
if (a[key] > b[key])
return 1;
return 0;
}
function sortObject(o) {
var sorted = {},
key, a = [];
for (key in o) {
if (o.hasOwnProperty(key)) {
a.push(key);
}
}
a.sort();
for (key = 0; key < a.length; key++) {
sorted[a[key]] = o[a[key]];
}
return sorted;
}
function isEqual(array1, array2) {
array1 = array1.map(x => sortObject(x)).sort(compare);
array2 = array2.map(x => sortObject(x)).sort(compare);
if (JSON.stringify(array1) === JSON.stringify(array2))
return true;
else return false;
}
console.log('Are x and y equal ==> ' + isEqual(x, y));
console.log('Are a and b equal ==> ' + isEqual(a, b));
console.log('Are p and q equal ==> ' + isEqual(p, q));
Interesting question. Here is a solution which works by sorting the arrays and then using !_.isEqual to compare them:
let x=[{_id:"1",name:"abc"},{_id:"2",name:"def"}]
let y=[{_id:"1",name:"abc"},{_id:"3",name:"def"}]
let a=[{_id:"1",name:"abc"},{_id:"2",name:"def"}]
let b=[{_id:"2",name:"def"},{_id:"1",name:"abc"}]
let p=[{_id:"1",name:"abc"},{_id:"2",name:"def"}]
let q=[{_id:"1",name:"abc"},{_id:"2",name:"def"}]
const isDifferent = (a, b) => {
const sortArray = (arr) => _.sortBy(arr, ['id', 'name'])
return !_.isEqual(sortArray(a), sortArray(b))
}
console.log('x & y: ', isDifferent(x,y))
console.log('a & b: ', isDifferent(a,b))
console.log('p & q: ', isDifferent(p,q))
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.10/lodash.min.js"></script>
I have an array which consists of String numbers which consist of 3 point such as "1.452", "11.3.2","12".
For example if I sort this array
$scope.myArray=["11","14.2","9.2.1","5.6.3","0.9","6.7.2","2","1"];
I want to see this array like so
0.9,
1,
2,
5.6.3,
6.7.2,
9.2.1,
11,
14.2
I want to sort these values in descending order. How can I do this with AngularJS ?
Thank you in advance.
It's not pretty, but I think it works:
var myArray = ["11", "14.2", "9.2.1", "5.6.3", "0.9", "6.7.2", "2", "1"];
function compare(a, b) {
let aa = a.split(".");
let bb = b.split(".");
for (let i = 0; i < aa.length; i++) {
if (parseInt(aa[i]) > parseInt(bb[i])) {
return 1;
} else if (parseInt(aa[i]) < parseInt(bb[i])) {
return -1;
}
}
return -1;
}
myArray = myArray.sort(function(a, b) {
return compare(a, b)
})
console.log(myArray);
So all you need is to write your custom comparator for Array.prototype.sort() function. Let's look at the example below (I'll try to explain it in the comments)
const compareValues = (a, b) => {
// for each element which we compare we need to split it using '.' to get comparable integers
const aNumbers = a.split('.');
const bNumbers = b.split('.');
// then we start a look over the received arrays
for (let i = 0; i < aNumbers.length || i < bNumbers.length; i++) {
// here we take a current element. If we doesn't exist we consider it as 0
let currentA = parseInt(aNumbers[i]) || 0;
let currentB = parseInt(bNumbers[i]) || 0;
if (currentA === currentB) {
// if the numbers are equal, we go to the next pair of items
continue;
} else {
// otherwise we return the difference between them, which says to sort() function which one is bigger
return currentA - currentB;
}
}
// if nothing was returned from the above for statement all numbers are equal
return 0;
};
// here's the array, that you want to sort
const arr = ["11","14.2","9.2.1","5.6.3","0.9","6.7.2","2","1"];
// and just call the sort function with our comparator.
const sortedArr = arr.sort(compareValues);
function str_replace(str , part_to_replace , replace_with) {
var res = str.replace(part_to_replace , replace_with);
return res;
}
console.log(str_replace("amir" , "ir" , "er")) //returns "amer"
I want the function to return "e" which is the only part that changed aka replaced part so how i am supposed to do that ?
thanks in advance.
You could iterate all characters and take only the changed ones.
function check(a, b) {
if (a.length !== b.length) { return; }
return b
.split('') // take an array
.filter(function (c, i) { // filter
return a[i] !== c; // check characters
})
.join(''); // return string
}
function str_replace(str, part_to_replace, replace_with) {
return str.replace(part_to_replace, replace_with);
}
console.log(str_replace("amir", "ir", "er"));
console.log(check("amir", str_replace("amir", "ir", "er")));
It looks like you want an array of characters in the new string that were not present in the old one. This will do the trick:
function getDifference(oldStr, newStr) {
// .split('') turns your string into an array of characters
var oldSplit = oldStr.split('');
var newSplit = newStr.split('');
// then compare the arrays and get the difference
var diff = [];
for (var i = 0; i < newSplit.length; i++) {
if (newSplit[i] !== oldSplit[i]) {
diff.push(newSplit[i]);
}
}
return diff;
}
var diff = getDifference('amir', str_replace('amir', 'ir', 'er'));
console.log(diff); // e
I've created this codepen http://codepen.io/PiotrBerebecki/pen/ZWxvzm when trying to find an array containing symmetric difference of two or more arrays.
My function works OK but only if four arguments are passed. How can I modify my function so that it can accept an unknown number of arguments? There is a potentially repeatable block of code that perhaps could be part of a for loop or reduce / map methods. I can't figure out how to accomplish this.
symmetricDifference([1,2,3,4], [3,4,5,6], [2,4,6,7], [8,9])
// should return an array containing [1,4,5,7,8,9]
symmetricDifference([1,2,3,4], [3,4,5,6])
// should return an array containing [1,2,5,6]
var arrA = [1,2,3,4];
var arrB = [3,4,5,6];
var arrC = [2,4,6,7];
var arrD = [8,9];
function symmetricDifference(arr) {
let args = Array.prototype.slice.call(arguments);
let result = [];
result = args[0].concat(args[1]).filter(function(item) {
return args[0].indexOf(item) === -1 || args[1].indexOf(item) === -1;
});
result = result.concat(args[2]).filter(function(item) {
return result.indexOf(item) === -1 || args[2].indexOf(item) === -1;
});
result = result.concat(args[3]).filter(function(item) {
return result.indexOf(item) === -1 || args[3].indexOf(item) === -1;
});
return result;
}
Thanks to the hints by #Bergi I've introduced a for loop and an initial value var result = args[0]; The function is working now as desired as it accepts an unknown number of arguments. I've updated the original codepen (http://codepen.io/PiotrBerebecki/pen/ZWxvzm) to demonstrate this implementation.
function symmetricDifference(arr) {
let args = Array.prototype.slice.call(arguments);
let result = args[0];
for (var i = 1; i < args.length; i++) {
result = result.concat(args[i]).filter(function(item) {
return result.indexOf(item) === -1 || args[i].indexOf(item) === -1;
});
}
// remove duplicates and sort
return Array.from(new Set(result)).sort((a, b) => a - b);
}
First time poster, long time reader. I’m having a problem sorting an array of objects, this is homework so I’m not asking for someone to write the code for me just point me in the right direction or show me my over sight. The object is to write a function to sort an array of objects when passing in an array and a key ie:
([{a:2},{b:2},{a:1},{a:3},{b:3},{b:1}], “a”)
Should return
[{a:1},{a:2},{a:3},{b:1},{b:2},{b:3}];
I can’t use anything like underscore.js or node.js
//example array to use
var testarr = [{a:2},{b:2},{a:1},{a:3},{b:3},{b:1}];
console.log("array sort test: should look like [{a:1},{a:2},{a:3},{b:1},{b:2},{b:3}]");
//first attempt
var sortArrayByKey = function (arr1, key) {
(arr1.sort(function(a,b){
return a[key] - b[key];}));
return arr1;
};
//still only returns testarr
console.log(sortArrayByKey(testarr, "a") );
//second attempt
var sortArrayByKey1 = function (array, key) {
var compareByKey = function (a, b) {
var x = a[key]; var y = b[key];
return x - y;
}
array.sort(compareByKey);
return array;
};
//still only returns testarr
console.log(sortArrayByKey1(testarr, “a”));
![pic of requirements in-case i'm describing it wrong photo
Here's my solution. I made it so you can also add more keys and sort them too.
Fiddle - http://jsfiddle.net/Q7Q9C/3/
function specialSort(arrayToSort, keyOrder) {
arrayToSort = arrayToSort.sort(function (a, b) {
for (var key in keyOrder) {
if (!keyOrder.hasOwnProperty(key)) {
continue;
}
var aKey = keyOrder[key];
if (typeof a[aKey] === "undefined" && typeof b[aKey] === "undefined") {
continue;
}
if (typeof a[aKey] !== "undefined" && typeof b[aKey] === "undefined") {
return -1;
}
if (typeof a[aKey] === "undefined" && typeof b[aKey] !== "undefined") {
return 1;
}
if (a[aKey] > b[aKey]) {
return 1;
}
else if (a[aKey] < b[aKey]) {
return -1;
}
}
return 0;
});
return arrayToSort;
}
var arrayToSort = [
{a:2},
{b:2},
{a:1},
{a:3},
{b:3},
{c:3},
{c:2},
{b:1}
];
var keyOrder = ["a", "b", "c"];
var sortedArray = specialSort(arrayToSort, keyOrder);
console.log(JSON.stringify(sortedArray));
Hmm.. this is a weird one. First you need to check if one of the keys is the priority key and sort based on that. Then if both keys are equal sort by the values. The problem is that there is no straightforward way to get the key but you can use the for .. in loop.
I'm going to assume that each object contains only one property otherwise the code will not make sense since property is unordered in objects:
function sortPreferredKey(arr,key) {
arr.sort(function(a,b){
// get the keys of each object
for (var a_key in a) {break}
for (var b_key in b) {break}
if (a_key != b_key) {
if (a_key == key) return 1;
else if (b_key == key) return -1;
else return 0;
}
return a[a_key] - b[b_key];
});
}
I may have gotten the order of sort wrong but you get the idea. It's really weird that you'd even need to do something like this.
This is the best I can come up with. It will sort all the elements with the given key to the front; the elements without the key will be in the back, but they'll be in an unpredictable order.
function sortArrayByKey(arr, key) {
function compareKey(a, b) {
if (a.hasOwnProperty(key)) {
if (b.hasOwnProperty(key)) {
return a[key] - b[key];
} else {
return -1;
}
} else if (b.hasOwnProperty(key)) {
return 1;
} else {
return 0;
}
}
arr.sort(compareKey);
return arr;
}
The documentation for the sort method is here. The compare function:
should be a function that accepts two arguments x and y and returns a
negative value if x < y, zero if x = y, or a positive value if x > y.
The function is passed the values in the array, so it's like calling the function with:
compareFunction({a:2},{b:2});
What you seem to want to do is sort on the property name first, then on the value. The problem with that is that you can't guarantee what order the property names are returned in. In this case, if you have exactly one own property for each object, you can do:
// Return first own property returned by in
// ORDER IS NOT GUARANTEED
function getPropName(o) {
for (var p in o) {
if (o.hasOwnProperty(p)) {
return p;
}
}
}
function specialSort(array, key) {
array.sort(function (a, b) {
var aProp = getPropName(a);
var bProp = getPropName(b);
// If properties are the same, compare value
if (aProp == bProp) {
return a[aProp] - b[bProp];
}
// Otherwise, compare keys
return aProp == key? -1 : bProp == key? 1 : aProp.charCodeAt(0) - bProp.charCodeAt(0);
});
return array;
}
The above will also sort any other keys (c, d, e, etc.) after the preferred key so:
var a = [{c:3},{a:2},{b:2},{c:2},{a:1},{a:3},{b:3},{b:1},{c:1}]
specialSort(a, 'b'); // [{b:1}, {b:2}, {b:3}, {a:1}, {a:2}, {a:3}, {c:1}, {c:2}, {c:3}]
Here's a solution that makes a guess what to do if neither object being compared in the array has the passed in comparison key:
var data = [{a:2},{b:2},{a:1},{a:3},{b:3},{b:1}];
function sortByProperty(array, propName) {
function findFirstProperty(obj) {
for (x in obj) {
if (obj.hasOwnProperty(x)) {
return x;
}
}
}
return array.sort(function(first, second) {
var firstHasProp = propName in first;
var secondHasProp = propName in second;
if (firstHasProp) {
if (secondHasProp) {
// both have the property
return first[propName] - second[propName];
} else {
// only first has the property
return -1;
}
} else if (secondHasProp){
// only second has the property
return 1;
} else {
// Neither sort candidate has the passed in property name
// It is not clear what you want to do here as no other property
// name has been specified
return first[findFirstProperty(first)] - second[findFirstProperty(second)]
}
});
}
Working demo: http://jsfiddle.net/jfriend00/PFurT/
Logically, here's what it does:
If both comparison candidates have the desired property, then simply sort by the value of that property.
If only one comparison candidate has the desired property, then make the one with the desired property be first in the sort order
If neither comparison candidate has the desired property, find the first other property on the object and sort by that. This is a guess because you don't really explain what you want to happen in this case, but it works for the data example you provided.
Here's a version that works like the above one, but is has been extended to sort properties that are not the passed in property in alpha order and to deal with empty objects (with no properties) so they go at the end of the sort:
var data = [{c:4},{a:2},{b:2},{a:1},{a:3},{b:3},{b:1},{},{c:3}];
function sortByProperty(array, propName) {
function findFirstProperty(obj) {
for (x in obj) {
if (obj.hasOwnProperty(x)) {
return x;
}
}
}
return array.sort(function(first, second) {
var firstHasProp = propName in first;
var secondHasProp = propName in second;
if (firstHasProp) {
if (secondHasProp) {
// both have the property
return first[propName] - second[propName];
} else {
// only first has the property
return -1;
}
} else if (secondHasProp){
// only second has the property
return 1;
} else {
// Neither sort candidate has the passed in property name
// It is not clear what you want to do here as no other property
// name has been specified
var firstProp = findFirstProperty(first);
var secondProp = findFirstProperty(second);
if (firstProp === undefined && secondProp === undefined) {
return 0;
} else if (firstProp === undefined) {
return 1;
} else if (secondProp === undefined) {
return -1;
}
else if (firstProp === secondProp) {
return first[firstProp] - second[secondProp];
} else {
return firstProp.localeCompare(secondProp);
}
}
});
}
Working demo: http://jsfiddle.net/jfriend00/6QsVv/