Swapping two properties of objects with function in javascript - javascript

I am trying to write a function that will take two objects, people in this case, and swap only two of their attributes. Here is my function for the Person:
function Person (tall, weight, gender, iq, favoriteColor) {
this.tall = tall;
this.weight = weight;
this.gender = gender;
this.iq = iq;
this.favoriteColor = favoriteColor;
}
var joe = new Person("6-2", 180, "male", 130, "blue");
var bob = new Person("5-11", 150, "male", 120, "red");
So i want to swap JUST their IQs and favoriteColor.
So far I have:
function Swap(a, b) {
var i = a;
a = b;
b = i;
console.log(a, b);
}
This obviously swaps all their properties, but i cannot figure out how to swap just two and still have them log as objects. I have tried:
function Swap(a, b) {
var a = a.iq + a.favoriteColor;
var b = b.iq + b.favoriteColor;
var i = a;
a = b;
b = i;
console.log(a, b);
}
but this returns in the console:
120red 130blue.
Technically it swapped the two values, but their structure as an object is gone and the other three properties that they were supposed to keep of their own are also gone. How do I write the swap function to do this?
Thanks!

This is what you want. You need to swap the individual fields. You can't add them like you are doing. Also, it's best not to use the same name for variables that you've already declared, it's just too confusing.
function Swap(a, b) {
var i = a.iq;
a.iq = b.iq;
b.iq = i;
i = a.favoriteColor;
a.favoriteColor= b.favoriteColor;
b.favoriteColor = i;
console.log(a, b);
}

function Swap(a, b) {
var newBIq = a.iq
var newBColor = a.favoriteColor;
var newAIq = b.iq
var newAColor = b.favoriteColor;
a.iq = newAIq;
a.favoriteColor = newAColor;
b.iq = newBIq;
b.favoriteColor = newBColor
console.log(a, b);
}
Here you see the 4 values needed. I hope the naming helps understanding better than just i,j :D

If we take this solution to swap values...
b = [a, a = b][0];
...we could do this...
function Swap(a, b) {
b.iq = [a.iq, a.iq = b.iq][0];
b.favoriteColor = [a.favoriteColor, a.favoriteColor = b.favoriteColor][0];
}
and if you can use ECMAScript 6, you could even do
function Swap(a, b) {
[a.iq, b.iq] = [b.iq, a.iq]
[a.favoriteColor, b.favoriteColor] = [b.favoriteColor, a.favoriteColor]
}

This will swap all the values for the keys in an array of keys between objects a and b:
function Swap(a,b, keys){
for(var i=0; i<keys.length; i++){
var currentKey = keys[i];
var temp = a[currentKey];
a[currentKey] = b[currentKey];
b[currentKey] = temp;
}
}

Related

How do I merge two dictionaries in Javascript? [duplicate]

This question already has answers here:
How can I merge properties of two JavaScript objects dynamically?
(69 answers)
Closed 1 year ago.
var a = {};
a['fruit'] = "apple";
var b = {};
b['vegetable'] = "carrot";
var food = {};
The output variable 'food' must include both key-value pairs.
You could use Object.assign.
var a = { fruit: "apple" },
b = { vegetable: "carrot" },
food = Object.assign({}, a, b);
console.log(food);
For browser without supporting Object.assign, you could iterate the properties and assign the values manually.
var a = { fruit: "apple" },
b = { vegetable: "carrot" },
food = [a, b].reduce(function (r, o) {
Object.keys(o).forEach(function (k) { r[k] = o[k]; });
return r;
}, {});
console.log(food);
Ways to achieve :
1. Using JavaScript Object.assign() method.
var a = {};
a['fruit'] = "apple";
var b = {};
b['vegetable'] = "carrot";
var food = Object.assign({}, a, b);
console.log(food);
2. Using custom function.
var a = {};
a['fruit'] = "apple";
var b = {};
b['vegetable'] = "carrot";
function createObj(obj1, obj2){
var food = {};
for (var i in obj1) {
food[i] = obj1[i];
}
for (var j in obj2) {
food[j] = obj2[j];
}
return food;
};
var res = createObj(a, b);
console.log(res);
3. Using ES6 Spread operator.
let a = {};
a['fruit'] = "apple";
let b = {};
b['vegetable'] = "carrot";
let food = {...a,...b}
console.log(food)
You could use the spread operator in es6, but you would need to use babel to transpile the code to be cross browser friendly.
const a = {};
a['fruit'] = "apple";
const b = {};
b['vegetable'] = "carrot";
const food = { ...a, ...b }
console.log(food)
Create a Utility function which can extend Objects, like:
function extendObj(obj1, obj2){
for (var key in obj2){
if(obj2.hasOwnProperty(key)){
obj1[key] = obj2[key];
}
}
return obj1;
}
And then extend this food object with the another Objects. Here is example:
food = extendObj(food, a);
food = extendObj(food, b);

removes elements from array javascript (contrary intersection)

Yesterday nigth I maked this question Delete elements from array javascript
But I mistook, my explanation and my example were about an intersection between two arrays.
What I wanted to ask is about how remove elements on array that doesn´t exist on other array.
Example:
Array A=> [a, b, c, d]
Array B=> [b, d, e]
Array C= removeElementsNotIn(A, B);
Array C (after function)-> [a,c]
Thank you very much.
You can use .filter() to selectively remove items that don't pass a test.
var c = a.filter(function(item) {
return b.indexOf(item) < 0; // Returns true for items not found in b.
});
In a function:
function removeElementsNotIn(a, b) {
return a.filter(function(item) {
return b.indexOf(item) < 0; // Returns true for items not found in b.
});
}
var arrayC = removeElementsNotIn(arrayA, arrayB);
If you want to get really fancy (advanced only), you can create a function that returns the filtering function, like so:
function notIn(array) {
return function(item) {
return array.indexOf(item) < 0;
};
}
// notIn(arrayB) returns the filter function.
var c = arrayA.filter(notIn(arrayB));
Thanks Second Rikhdo
full code:
var a = [1,2,3,4,5];
var b = [4,5,6,7,8,9];
var new_array = a.filter(function(item) {
return b.indexOf(item) < 0; // Returns true for items not found in b.
});
alert(new_array);
// results: array[1,2,3]
Demo: https://jsfiddle.net/cmoa7Lw7/
a1 = ['s1', 's2', 's3', 's4', 's5'];
a2 = ['s4', 's5', 's6'];
a3 = [];
function theFunction(ar1, ar2) {
var ar3 = [];
for (var i = 0; i < a1.length; i++) {
if (ar2.indexOf(ar1[i]) != -1) {
ar3.push(ar1[i]);
}
}
return ar3;
}
a3 = theFunction(a1, a2);
document.getElementById('out').innerHTML = a3.toString();
<div id="out"></div>
2022 answer
There is one more alternative which is easier to read:
const c = a.filter(item => !b.includes(item))

Default value for object

I am using the Canvas 2d context to write text to the screen..
To accomplish this I have it run through an array of text objects that I created, right now I have the text objects with 3 properties:
text.text
text.x
text.y
text.text holds the string to write, text.x holds the value for the x position, and text.y holds the value for the y position
Is there anyway I could skip the text.text property?
so for example, right now it looks something like this:
var textStrings = [];
textStrings[0] = {};
textStrings[0].text = "hello";
textStrings[0].x = 0;
textStrings[0].y = 10;
textStrings[1] = {};
textStrings[1].text = "world";
textStrings[1].x = 10;
textStrings[1].y = 10;
But is there any way that I could do something like this instead:
textStrings = [];
textStrings[0] = {};
textStrings[0] = "hello";
textStrings[0].x = "0";
textStrings[0].y = 10;
textStrings[1] = {};
textStrings[1] = "world";
textStrings[1].x = 10;
textStrings[1].y = 10;
basically a default property of an object or something...
right now as soon as I do something like
textStrings[0] = "hello";
it changes textStrings to a string instead of an object, and then I can no longer add properties to it, since its a primitive data type.
Thanks
You can use String objects instead of primitive values:
var a = new String("hello");
a.x = "0";
a.y = 10;
var b = new String("world");
b.x = "10";
b.y = 10;
var textStrings = [a, b];
You might also use special objects. The toString method is automatically used when the object is to be converted to a string:
function Text(t, x, y) {
this.text = t; this.x = x; this.y = y;
}
Text.prototype.toString = function() { return this.text; }
alert(new Text("hello", 0, 0)); // implicit string conversion
console.log(""+new Text("world", 10, 10)); // explicit string conversion
I guess you would have such a constructor function anyway, to simplify the syntax for the textStrings array.
If your text strings are guaranteed to be unique, you could use them for indexing:
var textStrings = {};
textStrings["world"].x = 10;
textStrings["world"].y = 10;
and then you could get a list of your "text" strings (so that you can index through your object) using the following snippet:
textkeys : function (textStrings) {
var accumulator = [];
for (var propertyName in o) {
arr.push(propertyName);
}
return accumulator;
}
from snipplr
Similar to the idea of #Bergi, but using a functional approach for creating the objects:
var textCreator = function (text, x, y) {
var that = {};
that.text = text;
that.x = x;
that.y = y;
that.toString = function () {
return text;
}
return that;
};
textStrings = [];
textStrings[0] = textCreator("hello", 0 ,10);
textStrings[1] = textCreator("world", 10, 10);
And just for completeness: you could extend the String prototype, but that is not advisable, and is practically the same as one of the solutions provided by Bergi.
String.prototype.x = null;
String.prototype.y = null;
textStrings = [];
//textStrings[0] = "hello";
textStrings[0] = new String("hello");
textStrings[0].x = "0";
textStrings[0].y = 10;
//textStrings[1] = "world";
textStrings[1] = new String("world");
textStrings[1].x = 10;
textStrings[1].y = 10;

My array data is being corrupted somehow by my custom (Set Theory) Complements() function?

I was fed up with the limited javascript Array functions and wanted to write a few of my own handy prototype functions to perform Set Theory functions.
Below is the code I have for this so far
<script type="text/javascript">
Array.prototype.contains = function(obj) {
var i = this.length;
while (i--) {
if (this[i] === obj) {
return true;
}
}
return false;
}
Array.prototype.getIndices = function(obj){
var indices = new Array();
var i = this.length;
while (i--) {
if(this[i] === obj){
indices.push(i);
}
}
return indices;
}
Array.prototype.Union = function(arr){
//combines two arrays together to return a single array containing all elements (once)
//{1,2,3,4,5}.Union({3,4,5,6,7})
//returns: {1,2,3,4,5,6,7}
var primArray = this;
var secondArray = arr;
var i = primArray.length;
while(i--){
if(secondArray.contains(primArray[i])){
primArray.splice(i, 1);
}
}
var returnArr = primArray.concat(secondArray);
return returnArr;
}
Array.prototype.Intersection = function(arr){
//Returns an array of elements that are present in both sets
//{1,2,3,4,5}.Intersection({3,4,5,6,7})
//returns: {3,4,5}
var primArray = this;
var secondArray = arr;
var returnArr = new Array;
var i = 0;
while(i++<primArray.length){
if(secondArray.contains(primArray[i])){
returnArr.push(primArray[i]);
}
}
return returnArr;
}
Array.prototype.Complement = function(arr){
//Returns an array of elements that are only in the primary (calling) element
//{1,2,3,4,5}.Complement({3,4,5,6,7})
//return: {1,2}
var primArray = this;
var secondArray = arr;
var i = primArray.length;
while(i--){
if(secondArray.contains(primArray[i])){
primArray.splice(i, 1);
}
}
return primArray;
}
Array.prototype.SymmetricDifference = function(arr){
//Returns elements that are exclusive to each set
//{1,2,3,4,5}.SymmetricDifference({3,4,5,6,7})
//return: {1,2,6,7}
var primArray = this;
var secondArray = arr;
var i = primArray.length;
while(i--){
if(secondArray.contains(primArray[i])){
var indices = secondArray.getIndices(primArray[i]);
primArray.splice(i, 1);
var j=indices.length;
while(j--){
secondArray.splice(indices[j], 1);
}
}
}
var returnArr = primArray.concat(arr);
return returnArr;
}
function run(){
var Q = "A";
var D = [1,2,3,4,5,6,7,8,9,10];
var sets = {
"A":[1,2,3],
"B":[3,4,5],
"C":[5,6,7]
}
var R = D;
for(var el in sets){
R = R.Complement(sets[el]);
}
//if I alert D at this point I get 8,9,10 instead of 1,2,3,4,5,6,7,8,9,10 as I would expect? What am I missing here... It causes a problem when I perform D.Complement(R) later on
document.write(R + "<br/>");
R = R.Union(sets[Q]);
document.write(R + "<br/>");
//Here!
R = D.Complement(R);
document.write(R);
}
</script>
</head>
<body onload="run()">
</body>
</html>
Everything is working up to the final point when I then try to get the complement of the domain and my newly constructed set. I am expected to be getting the complement of [1,2,3,4,5,6,7,8,9,10] and [8,9,10,1,2,3] which would yield [4,5,6,7] but when I perform D.Complement(R) my D variable seems to have turned into [1,2,3]. This appears to happen after the enumeration I perform.
I thought it might be because I was using this.splice and arr.splice in my functions and when I was passing the variables to the functions they were being passed as pointers meaning I was actually working on the actual memory locations. So I then used primArray and secondArray to create a duplicate to work on... but the problem is still happening
Many Thanks
So I then used primArray and secondArray to create a duplicate to work on... but the problem is still happening
Just assigning it to a variable does not make it a new array, you are still working on the array that was passed in. You have to manually make a new copy of the array either by looping through it and copy each index or by joining and splitting.

Getting a union of two arrays in JavaScript [duplicate]

This question already has answers here:
How to merge two arrays in JavaScript and de-duplicate items
(89 answers)
Closed 4 years ago.
Say I have an array of [34, 35, 45, 48, 49] and another array of [48, 55]. How can I get a resulting array of [34, 35, 45, 48, 49, 55]?
With the arrival of ES6 with sets and splat operator (at the time of being works only in Firefox, check compatibility table), you can write the following cryptic one liner:
var a = [34, 35, 45, 48, 49];
var b = [48, 55];
var union = [...new Set([...a, ...b])];
console.log(union);
Little explanation about this line: [...a, ...b] concatenates two arrays, you can use a.concat(b) as well. new Set() create a set out of it and thus your union. And the last [...x] converts it back to an array.
If you don't need to keep the order, and consider 45 and "45" to be the same:
function union_arrays (x, y) {
var obj = {};
for (var i = x.length-1; i >= 0; -- i)
obj[x[i]] = x[i];
for (var i = y.length-1; i >= 0; -- i)
obj[y[i]] = y[i];
var res = []
for (var k in obj) {
if (obj.hasOwnProperty(k)) // <-- optional
res.push(obj[k]);
}
return res;
}
console.log(union_arrays([34,35,45,48,49], [44,55]));
If you use the library underscore you can write like this
var unionArr = _.union([34,35,45,48,49], [48,55]);
console.log(unionArr);
<script src="https://cdnjs.cloudflare.com/ajax/libs/underscore.js/1.9.1/underscore-min.js"></script>
Ref: http://underscorejs.org/#union
I'm probably wasting time on a dead thread here. I just had to implement this and went looking to see if I was wasting my time.
I really like KennyTM's answer. That's just how I would attack the problem. Merge the keys into a hash to naturally eliminate duplicates and then extract the keys. If you actually have jQuery you can leverage its goodies to make this a 2 line problem and then roll it into an extension. The each() in jQuery will take care of not iterating over items where hasOwnProperty() is false.
jQuery.fn.extend({
union: function(array1, array2) {
var hash = {}, union = [];
$.each($.merge($.merge([], array1), array2), function (index, value) { hash[value] = value; });
$.each(hash, function (key, value) { union.push(key); } );
return union;
}
});
Note that both of the original arrays are left intact. Then you call it like this:
var union = $.union(array1, array2);
If you wants to concatenate two arrays without any duplicate value,Just try this
var a=[34, 35, 45, 48, 49];
var b=[48, 55];
var c=a.concat(b).sort();
var res=c.filter((value,pos) => {return c.indexOf(value) == pos;} );
function unique(arrayName)
{
var newArray=new Array();
label: for(var i=0; i<arrayName.length;i++ )
{
for(var j=0; j<newArray.length;j++ )
{
if(newArray[j]==arrayName[i])
continue label;
}
newArray[newArray.length] = arrayName[i];
}
return newArray;
}
var arr1 = new Array(0,2,4,4,4,4,4,5,5,6,6,6,7,7,8,9,5,1,2,3,0);
var arr2= new Array(3,5,8,1,2,32,1,2,1,2,4,7,8,9,1,2,1,2,3,4,5);
var union = unique(arr1.concat(arr2));
console.log(union);
Adapted from: https://stackoverflow.com/a/4026828/1830259
Array.prototype.union = function(a)
{
var r = this.slice(0);
a.forEach(function(i) { if (r.indexOf(i) < 0) r.push(i); });
return r;
};
Array.prototype.diff = function(a)
{
return this.filter(function(i) {return a.indexOf(i) < 0;});
};
var s1 = [1, 2, 3, 4];
var s2 = [3, 4, 5, 6];
console.log("s1: " + s1);
console.log("s2: " + s2);
console.log("s1.union(s2): " + s1.union(s2));
console.log("s2.union(s1): " + s2.union(s1));
console.log("s1.diff(s2): " + s1.diff(s2));
console.log("s2.diff(s1): " + s2.diff(s1));
// Output:
// s1: 1,2,3,4
// s2: 3,4,5,6
// s1.union(s2): 1,2,3,4,5,6
// s2.union(s1): 3,4,5,6,1,2
// s1.diff(s2): 1,2
// s2.diff(s1): 5,6
I like Peter Ajtai's concat-then-unique solution, but the code's not very clear. Here's a nicer alternative:
function unique(x) {
return x.filter(function(elem, index) { return x.indexOf(elem) === index; });
};
function union(x, y) {
return unique(x.concat(y));
};
Since indexOf returns the index of the first occurence, we check this against the current element's index (the second parameter to the filter predicate).
Shorter version of kennytm's answer:
function unionArrays(a, b) {
const cache = {};
a.forEach(item => cache[item] = item);
b.forEach(item => cache[item] = item);
return Object.keys(cache).map(key => cache[key]);
};
You can use a jQuery plugin: jQuery Array Utilities
For example the code below
$.union([1, 2, 2, 3], [2, 3, 4, 5, 5])
will return [1,2,3,4,5]
function unite(arr1, arr2, arr3) {
newArr=arr1.concat(arr2).concat(arr3);
a=newArr.filter(function(value){
return !arr1.some(function(value2){
return value == value2;
});
});
console.log(arr1.concat(a));
}//This is for Sorted union following the order :)
function unionArrays() {
var args = arguments,
l = args.length,
obj = {},
res = [],
i, j, k;
while (l--) {
k = args[l];
i = k.length;
while (i--) {
j = k[i];
if (!obj[j]) {
obj[j] = 1;
res.push(j);
}
}
}
return res;
}
var unionArr = unionArrays([34, 35, 45, 48, 49], [44, 55]);
console.log(unionArr);
Somewhat similar in approach to alejandro's method, but a little shorter and should work with any number of arrays.
function unionArray(arrayA, arrayB) {
var obj = {},
i = arrayA.length,
j = arrayB.length,
newArray = [];
while (i--) {
if (!(arrayA[i] in obj)) {
obj[arrayA[i]] = true;
newArray.push(arrayA[i]);
}
}
while (j--) {
if (!(arrayB[j] in obj)) {
obj[arrayB[j]] = true;
newArray.push(arrayB[j]);
}
}
return newArray;
}
var unionArr = unionArray([34, 35, 45, 48, 49], [44, 55]);
console.log(unionArr);
Faster
http://jsperf.com/union-array-faster
I would first concatenate the arrays, then I would return only the unique value.
You have to create your own function to return unique values. Since it is a useful function, you might as well add it in as a functionality of the Array.
In your case with arrays array1 and array2 it would look like this:
array1.concat(array2) - concatenate the two arrays
array1.concat(array2).unique() - return only the unique values. Here unique() is a method you added to the prototype for Array.
The whole thing would look like this:
Array.prototype.unique = function () {
var r = new Array();
o: for(var i = 0, n = this.length; i < n; i++)
{
for(var x = 0, y = r.length; x < y; x++)
{
if(r[x]==this[i])
{
continue o;
}
}
r[r.length] = this[i];
}
return r;
}
var array1 = [34,35,45,48,49];
var array2 = [34,35,45,48,49,55];
// concatenate the arrays then return only the unique values
console.log(array1.concat(array2).unique());
Just wrote before for the same reason (works with any amount of arrays):
/**
* Returns with the union of the given arrays.
*
* #param Any amount of arrays to be united.
* #returns {array} The union array.
*/
function uniteArrays()
{
var union = [];
for (var argumentIndex = 0; argumentIndex < arguments.length; argumentIndex++)
{
eachArgument = arguments[argumentIndex];
if (typeof eachArgument !== 'array')
{
eachArray = eachArgument;
for (var index = 0; index < eachArray.length; index++)
{
eachValue = eachArray[index];
if (arrayHasValue(union, eachValue) == false)
union.push(eachValue);
}
}
}
return union;
}
function arrayHasValue(array, value)
{ return array.indexOf(value) != -1; }
Simple way to deal with merging single array values.
var values[0] = {"id":1235,"name":"value 1"}
values[1] = {"id":4323,"name":"value 2"}
var object=null;
var first=values[0];
for (var i in values)
if(i>0)
object= $.merge(values[i],first)
You can try these:
function union(a, b) {
return a.concat(b).reduce(function(prev, cur) {
if (prev.indexOf(cur) === -1) prev.push(cur);
return prev;
}, []);
}
or
function union(a, b) {
return a.concat(b.filter(function(el) {
return a.indexOf(el) === -1;
}));
}
ES2015 version
Array.prototype.diff = function(a) {return this.filter(i => a.indexOf(i) < 0)};
Array.prototype.union = function(a) {return [...this.diff(a), ...a]}
If you want a custom equals function to match your elements, you can use this function in ES2015:
function unionEquals(left, right, equals){
return left.concat(right).reduce( (acc,element) => {
return acc.some(elt => equals(elt, element))? acc : acc.concat(element)
}, []);
}
It traverses the left+right array. Then for each element, will fill the accumulator if it does not find that element in the accumulator. At the end, there are no duplicate as specified by the equals function.
Pretty, but probably not very efficient with thousands of objects.
I think it would be simplest to create a new array, adding the unique values only as determined by indexOf.
This seems to me to be the most straightforward solution, though I don't know if it is the most efficient. Collation is not preserved.
var a = [34, 35, 45, 48, 49],
b = [48, 55];
var c = union(a, b);
function union(a, b) { // will work for n >= 2 inputs
var newArray = [];
//cycle through input arrays
for (var i = 0, l = arguments.length; i < l; i++) {
//cycle through each input arrays elements
var array = arguments[i];
for (var ii = 0, ll = array.length; ii < ll; ii++) {
var val = array[ii];
//only add elements to the new array if they are unique
if (newArray.indexOf(val) < 0) newArray.push(val);
}
}
return newArray;
}
[i for( i of new Set(array1.concat(array2)))]
Let me break this into parts for you
// This is a list by comprehension
// Store each result in an element of the array
[i
// will be placed in the variable "i", for each element of...
for( i of
// ... the Set which is made of...
new Set(
// ...the concatenation of both arrays
array1.concat(array2)
)
)
]
In other words, it first concatenates both and then it removes the duplicates (a Set, by definition cannot have duplicates)
Do note, though, that the order of the elements is not guaranteed, in this case.

Categories

Resources