Search for an occurence in an object array - javascript

I don't know if I have the terminology right, but I have created the following function:
function myCollection(zip, municipality, info) {
this.myZip = zip;
this.myMuni = municipality;
this.myInfo= info;
}
Then I create the following array and add data to it:
var myArray = new Array();
myArray[0] = new myCollection("1000", "municipality A", "info A");
myArray[1] = new myCollection("2000", "municipality B", "info B");
myArray[2] = new myCollection("2000", "municipality C", "info C");
myArray[3] = new myCollection("3000", "municipality D", "info D");
What I would like to achieve:
search inside myArray where a certain zip code in myCollection occurs
display the rest of the data from myCollection for that zipcode
do the same for all other occurences of that same zipcode within the collection
A search for zip "2000" in the examply above should output:
2000, municipality B, info B
2000, municipality C, info C
My train of thoughts
I thought I'd find the occurences (indexes) where the string occurs and then retrieve the required data like this:
console.log(myArray[i].myInfo);
where i is the index within the array where
myArray[i].myZip
matches "2000".
However, I can't get the indexOf to work to search for a string within the object I created, nor can I retrieve all the other occurences that match the same criteria.
Did I choose the right way to do this to start with?
How should I approach this, if you know jQuery or other external libraries should be avoided?
I hope I'm a bit clear - thank you for your thoughts and advice.

You could use a good old while loop :
function findAll(array, fn) {
var result = [], i = -1;
while (++i < array.length) {
if (fn(array[i]) === true) result.push(array[i]);
}
return result;
}
Usage example :
var a = [{ a: 1 }, { a: 2 }, { a: 3 }];
var result = findAll(a, function (item) {
return item.a !== 2;
});
result; // [{ a: 1 }, { a: 3 }]

You can simply iterate over object:
search = function (arr, keyName, value) {
if (arr && keyName && value) {
var i, j = arr.length;
for (i = 0; i < j; i += 1) {
if (arr[i][keyName] === value) {
return {
index : i,
item : arr[i]
}
}
};
return {}
};
And then:
search(myArray, 'myZip', 2000);

In this case indexOf is current i value, so you can simply do var c = myArray[i]; to get collection, that satisfies your filter criteria. If you want to return more result than first collection found, simply add them sequentially to a new array and return it at the end.

Related

word combination in an array using javascript

Let's says I've an array['Alex', 'Sam', 'Robert']
I'd like to combine them something like:
Take first array[0] and append with array[2] which will be AlexRobert
first letter of array[0] which is A and append with array[2] that is Robert which will be ARobert
Take array[0] which is Alex and append with first letter of array[2] that is R which will be AlexR
Take first array[0] append with first letter of array[1] along with array[2] which will become AlexSRobert.
Basically the whole idea is when someone enter first name, middle name & last name I should be able to make combination and guess email ids. For example- Juan F. Nathaniel the array form will be like ['Juan', 'F', 'Nathaniel']
I want the combination of first, middle and last name like jaunn, jnathaniel, jaunfnathaniel
I'm beginner and here is what I've written:
var nameCombination = function(name){
var counting = name.split(" ");
for (var i=0; i<counting.length; i++){
console.log(counting[i] + counting[i+1]);
console.log(counting[i].split("",1) + counting[i+1]);
}
}
nameCombination('Alex Sam Robert');
I'm assuming you needed a function to do this? Here is a function to handle grabbing pieces of each index of the array. I'll leave it up to you to figure out what type of data you need...
var test = function() {
var array = ['Alex', 'Sam', 'Robert'];
var conditions = [{
index: 0,
length: array[0].length
},
{
index: 1,
length: 1
},
{
index: 2,
length: array[2].length
}]
alert(combine(array, conditions));
}
var combine = function(array, conditions) {
var output = "";
for(index in conditions) {
var condition = conditions[index];
var index = condition['index'];
var length = condition['length'];
output += array[index].substring(0, length);
}
return output;
}
test();
You could use an iterative and recursive approach for variable length of parts an their length.
function combine(array) {
function c(part, index) {
array[index].forEach(function (a) {
var p = part.concat(a);
if (p.length === array.length) {
r.push(p.join(''));
return;
}
c(p, index + 1);
});
}
var r = [];
c([], 0);
return r;
}
var input= ['Johann', 'Sebastian', 'Bach'],
array = input.map(function (a) { return ['', a[0], a]; });
result = combine(array);
console.log(result);
This problem can be solved using recursive approach.
var combinations = function(names, i, n){
if(i == n){
return [];
}
last_names = combinations(names, i + 1, n);
name_combinations = last_names.map(function(last_name){
return [
last_name,
names[i] + last_name,
names[i] + last_name[0],
names[i][0] + last_name,
names[i][0] + last_name[0]
]
});
name_combinations = [].concat.apply([], name_combinations);
name_combinations.push(names[i]);
return name_combinations;
};
var nameCombinations = function(name){
var name_array = name.split(' ');
return Array.from(new Set(combinations(name_array, 0, name_array.length)));
};
nameCombinations('first last');
above function can generate all the desired combinations for a given name.
for example: nameCombinations('first last') will return ["last", "firstlast", "firstl", "flast", "fl", "first"].
Ok without writing out every combination I will do the first few to give you the idea:
assuming
array[0] is the person's first name
array[1] is the person's middle name
array[2] is the person's last name
Firstname+Lastname:
var output = array[0] + array [2];
Firstname+Middlename:
var output1 = array[0] + array[1];
then then you could display the output using innerHTML:
Javascript:
document.getElementById("output").innerHTML = output + '<br>' + output1;
HTML:
<div id="output"></div>
Keep in mind you would need to keep doing that for the rest of the combinations.
Now for the combinations where you need to get the first letter of the variable you need to use charAt which I found from this stack overflow answer.
You would do the same thing as before, except instead you need to use charAt and do something like so:
Firstname+FirstLetterOfLastName:
var output2 = array[0] + array[2].charAt(0);
And you can output it using the same method as before.
If your still confused leave a comment and I will try and answer your questions.

Find the Words with an even number of occurrences in an Array - Javascript

Given an array of words, write a function that returns an array of the words that occur an even number of times.
function even(["hello", "hi", "hello", "elephant", "hi"]);
That output should be:
["hello", "hi"]
This has been a toy problem I have been struggling with recently. I have solved similar problems counting and returning the number of occurrences of elements in an array but am having trouble taking that logic and applying it to this problem.
This is what I have tried so far, but have hit a wall when trying to output just the even occurrences:
function even(collection) {
var results = [];
for(var i = 0; i < collection.length; i++){
var value = collection[i];
if(results[value]){
results[value] = results[value] + 1;
}else{
results[value] = 1;
}
}
return results;
}
You can use reduce to get an actual count of the words, then simply return an array of the ones that have an even count:
function even(wordsArr) {
//Object of words and counts
var wordCounts = wordsArr.reduce(function(counts, word) {
if (!counts.hasOwnProperty(word)) {
counts[word] = 0;
}
counts[word]++;
return counts;
}, {});
//Now filter that out and return
return Object.keys(wordCounts).filter(function(word) {
return wordCounts[word] % 2 === 0
});
}
even(["hello", "hi", "hello", "elephant", "hi"]); //["hello", "hi"]
var arr = ["hello", "hi", "hello", "elephant", "hi"];
function onlyEvens( arr )
{
var countObj = {};
for( var i = 0; i < arr.length; i++ )
{
var item = arr[i];
if( countObj[ item ] !== undefined )
countObj[item]++;
else
countObj[item] = 1;
}//for()
var filteredArray = [];
for(var key in countObj )
{
if( countObj[key] % 2 == 0 )
filteredArray.push( key );
}
return filteredArray;
}//onlyEvens()
console.log( onlyEvens( arr ) );
Issues in your code:
you use collection instead of words
you cannot access array the associative way. You must declare it as object:
results[value]
you return result variable, but it is undeclared.
return result;
results only contains the occurrences of every word. There miss the code that calculates if the occurrences of a word are odd or even.
fixed code:
function even(words) { // <<< in your code was collection
var results = {};
for(var i = 0; i < words.length; i++){
var value = words[i];
if(results[value]){
results[value] = results[value] + 1;
}else{
results[value] = 1;
}
}
var ret = [];
for(var word in results)
if(results[word]%2 !== 0)
rest.push(word);
return ret;
}
function even(list) {
var d = list.reduce(function(d, w) { d[w] = !d[w]; return d; }, {});
return Object.keys(d).filter(function(w) { return !d[w]; });
}
console.log(even(["hello", "hi", "hello", "elephant", "hi"]));
console.log(even(["hello", "yo", "yo", "hi", "hello", "yo", "elephant", "hi"]));
Explanation: Use the array .reduce() method to create an object (d) with a property for each word (w) with a boolean value indicating whether the word has an odd number of occurrences. Then .filter() the keys to get all the ones that are not odd.
If you previously sort the array you can filter it as required in just a code line like this :
var even = (str) => str.sort().filter((element, index, arr) => index+1 === arr.lastIndexOf(element));
console.log(even(["hello", "hello", "hi", "elephant", "hi", "hi"])); //[ 'hello', 'hi' ]

Match two values in different arrays

I am making a simple WebSockets chat, and have two arrays (this is server side, Node.js):
var clients = {1: "info about 1", 2: "info about 2", 3: "info about 3", 4: "info about four", 5: "info about five", 6: "info about six"};
var partners = [[1,3], [2,6], [5, 4]];
Now what I need to do, is look up a clients partner, in the partner array. So, for example, if my script returned 4, it would need to look up 4, and return 5, and if my script returned 1, it would return 3.
I tried just using partners[mynumber][0] but the problem is that mynumber could be either of the values, rather than just the first one.
Well, you have to look for that particular array first:
function partnerOf(someId) {
var res;
for (var i = 0, l = partners.length; i < l; i++) {
if (partners[i][0] === someId) {
res = partners[i][1];
break;
}
}
return res;
}
... but it looks (and is) quite cumbersome. An alternative would be to reorganize partners structure, turning it into an Object:
var partners = {
1: 3,
2: 6,
5: 4
};
Then look-up becomes trivial: you just evaluate partners[someId], that's all. Both more readable and way faster.
You could do
var possiblePartners=partners[mynumber];
var partnerNum=(possiblePartners[0]==myNumber)?possiblePartners[1]:possiblePartners[0];
However, the best thing to do would be to have an associative array with your partners, like this
var partners={1:3,2:6,5:4};
var partnerNum=partners[mynubmber];
Try this:
Array.prototype.different = function(arr2) {
var ret = [];
arr2.sort();
for(var i = 0; i < this.length; i += 1) {
if(arr2.indexOf( this[i] ) > -1){
ret.push( this[i] );
}
}
return ret;
};
Use like this
console.log(yourArray1.different(yourArray2));
I would change the structure of your data to allow easy partner finding
// defined partners DB
var partners = {};
// adds a chat from c1 to c2
function addChat(partners, c1, c2){
partners[c1] = c2;
partners[c2] = c1;
}
function findChatPartner(partners, c1){
return partners[c1];
}
You could use a for loop combined with an if/else statement
for (var i = 0, n = partners.length; i < n; i++) {
if (partners[i][0] === mynumber)
return partners[i][0];
else if (partners[i][1] === mynumber)
return partners[i][1];
}
It iterates through each set of numbers in the array until it finds mynumber, then returns the other number in that set

Remove duplicate objects from an array using javascript

I am trying to figure out an efficient way to remove objects that are duplicates from an array and looking for the most efficient answer. I looked around the internet everything seems to be using primitive data... or not scalable for large arrays. This is my current implementation which is can be improved and want to try to avoid labels.
Test.prototype.unique = function (arr, artist, title, cb) {
console.log(arr.length);
var n, y, x, i, r;
r = [];
o: for (i = 0, n = arr.length; i < n; i++) {
for (x = 0, y = r.length; x < y; x++) {
if (r[x].artist == arr[i].artist && r[x].title == arr[i].title) {
continue o;
}
}
r.push(arr[i]);
}
cb(r);
};
and the array looks something like this:
[{title: sky, artist: jon}, {title: rain, artist: Paul}, ....]
Order does not matter, but if sorting makes it more efficient then I am up for the challenge...
and for people who do not know o is a label and it is just saying jump back to the loop instead of pushing to the new array.
Pure javascript please no libs.
ANSWERS SO FAR:
The Performance Test for the answers below:
http://jsperf.com/remove-duplicates-for-loops
I see, the problem there is that the complexity is squared. There is one trick to do it, it's simply by using "Associative arrays".
You can get the array, loop over it, and add the value of the array as a key to the associative array. Since it doesn't allow duplicated keys, you will automatically get rid of the duplicates.
Since you are looking for title and artist when comparing, you can actually try to use something like:
var arrResult = {};
for (i = 0, n = arr.length; i < n; i++) {
var item = arr[i];
arrResult[ item.title + " - " + item.artist ] = item;
}
Then you just loop the arrResult again, and recreate the array.
var i = 0;
var nonDuplicatedArray = [];
for(var item in arrResult) {
nonDuplicatedArray[i++] = arrResult[item];
}
Updated to include Paul's comment. Thanks!
Here is a solution that works for me.
Helper functions:
// sorts an array of objects according to one field
// call like this: sortObjArray(myArray, "name" );
// it will modify the input array
sortObjArray = function(arr, field) {
arr.sort(
function compare(a,b) {
if (a[field] < b[field])
return -1;
if (a[field] > b[field])
return 1;
return 0;
}
);
}
// call like this: uniqueDishes = removeDuplicatesFromObjArray(dishes, "dishName");
// it will NOT modify the input array
// input array MUST be sorted by the same field (asc or desc doesn't matter)
removeDuplicatesFromObjArray = function(arr, field) {
var u = [];
arr.reduce(function (a, b) {
if (a[field] !== b[field]) u.push(b);
return b;
}, []);
return u;
}
and then simply call:
sortObjArray(dishes, "name");
dishes = removeDuplicatesFromObjArray(dishes, "name");
Basic sort-then-unique implementation, fiddle HERE:
function unique(arr) {
var comparer = function compareObject(a, b) {
if (a.title == b.title) {
if (a.artist < b.artist) {
return -1;
} else if (a.artist > b.artist) {
return 1;
} else {
return 0;
}
} else {
if (a.title < b.title) {
return -1;
} else {
return 1;
}
}
}
arr.sort(comparer);
console.log("Sorted: " + JSON.stringify(arr));
for (var i = 0; i < arr.length - 1; ++i) {
if (comparer(arr[i], arr[i+1]) === 0) {
arr.splice(i, 1);
console.log("Splicing: " + JSON.stringify(arr));
}
}
return arr;
}
It may or may not be the most efficient, and should be entirely scalable. I've added some console.logs so you can see it as it works.
EDIT
In the interest of saving on the space the function used, I did that for loop at the end, but it seems likely that didn't properly find only unique results (depsite it passing my simple jsfiddle test). Please try replacing my for loop with the following:
var checker;
var uniqueResults = [];
for (var i = 0; i < arr.length; ++i) {
if (!checker || comparer(checker, arr[i]) != 0) {
checker = arr[i];
uniqueResults.push(checker);
}
}
return uniqueResults;
I use this function. its not doing any sorting, but produces result. Cant say about performance as never measure it.
var unique = function(a){
var seen = [], result = [];
for(var len = a.length, i = len-1; i >= 0; i--){
if(!seen[a[i]]){
seen[a[i]] = true;
result.push(a[i]);
}
}
return result;
}
var ar = [1,2,3,1,1,1,1,1,"", "","","", "a", "b"];
console.log(unique(ar));// this will produce [1,2,3,"", "a", "b"] all unique elements.
Below is Henrique Feijo's answer with ample explanation and an example that you can cut and paste:
Goal: Convert an array of objects that contains duplicate objects (like this one)...
[
{
"id": 10620,
"name": "Things to Print"
},
{
"id": 10620,
"name": "Things to Print"
},
{
"id": 4334,
"name": "Interesting"
}
]
... Into an array of objects without duplicate objects (like this one):
[
{
"id": 10620,
"name": "Things to Print"
},
{
"id": 4334,
"name": "Interesting"
}
]
Explanation provided in the comments:
var allContent = [{
"id": 10620,
"name": "Things to Print"
}, {
"id": 10620,
"name": "Things to Print"
}, {
"id": 4334,
"name": "Interesting"
}]
//Put Objects Into As Associative Array. Each key consists of a composite value generated by each set of values from the objects in allContent.
var noDupeObj = {} //Create an associative array. It will not accept duplicate keys.
for (i = 0, n = allContent.length; i < n; i++) {
var item = allContent[i]; //Store each object as a variable. This helps with clarity in the next line.
noDupeObj[item.id + "|" + item.name] = item; //This is the critical step.
//Here, you create an object within the associative array that has a key composed of the two values from the original object.
// Use a delimiter to not have foo+bar handled like fo+obar
//Since the associative array will not allow duplicate keys, and the keys are determined by the content, then all duplicate content are removed.
//The value assigned to each key is the original object which is along for the ride and used to reconstruct the list in the next step.
}
//Recontructs the list with only the unique objects left in the doDupeObj associative array
var i = 0;
var nonDuplicatedArray = [];
for (var item in noDupeObj) {
nonDuplicatedArray[i++] = noDupeObj[item]; //Populate the array with the values from the noDupeObj.
}
console.log(nonDuplicatedArray)
For those who love ES6 and short stuff, here it's one solution:
const arr = [
{ title: "sky", artist: "Jon" },
{ title: "rain", artist: "Paul" },
{ title: "sky", artist: "Jon" }
];
Array.from(arr.reduce((a, o) => a.set(o.title, o), new Map()).values());
const arr = [
{ title: "sky", artist: "Jon" },
{ title: "rain", artist: "Paul" },
{ title: "sky", artist: "Jon" },
{ title: "rain", artist: "Jon" },
{ title: "cry", artist: "Jon" }
];
const unique = Array.from(arr.reduce((a, o) => a.set(o.title, o), new Map()).values());
console.log(`New array length: ${unique.length}`)
console.log(unique)
The above example only works for a unique title or id. Basically, it creates a new map for songs with duplicate titles.
Below code compares object with JSON as String format and removes duplicates and works fine with simple arrays.
Array.prototype.unique=function(a){
return function(){
return this.filter(a)
}
}(
function(a,b,c){
var tmp=[];
c.forEach(function(el){
tmp.push(JSON.stringify(el))
});
return tmp.indexOf(JSON.stringify(a),b+1)<0
})
If you are using underscore js, it is easy to remove duplicate object.
http://underscorejs.org/#uniq
function remove_duplicates(objectsArray) {
var arr = [], collection = [];
$.each(objectsArray, function (index, value) {
if ($.inArray(value.id, arr) == -1) {
arr.push(value.id);
collection.push(value);
}
});
return collection;
}

Count duplicates within an Array of Objects

I have an array of objects as follows within my server side JS:
[
{
"Company": "IBM"
},
{
"Person": "ACORD LOMA"
},
{
"Company": "IBM"
},
{
"Company": "MSFT"
},
{
"Place": "New York"
}
]
I need to iterate through this structure, detect any duplicates and then create a count of a duplicate is found along side each value.
Both of the values must match to qualify as a duplicate e.g. "Company": "IBM" is not a match for "Company": "MSFT".
I have the options of changing the inbound array of objects if needed. I would like the output to be an object, but am really struggling to get this to work.
EDIT: Here is the code I have so far where processArray is the array as listed above.
var returnObj = {};
for(var x=0; x < processArray.length; x++){
//Check if we already have the array item as a key in the return obj
returnObj[processArray[x]] = returnObj[processArray[x]] || processArray[x].toString();
// Setup the count field
returnObj[processArray[x]].count = returnObj[processArray[x]].count || 1;
// Increment the count
returnObj[processArray[x]].count = returnObj[processArray[x]].count + 1;
}
console.log('====================' + JSON.stringify(returnObj));
For example:
counter = {}
yourArray.forEach(function(obj) {
var key = JSON.stringify(obj)
counter[key] = (counter[key] || 0) + 1
})
Docs: Array.forEach, JSON.stringify.
Object.prototype.equals = function(o){
for(var key in o)
if(o.hasOwnProperty(key) && this.hasOwnProperty(key))
if(this[key] != o[key])
return false;
return true;
}
var array = [/*initial array*/],
newArray = [],
ok = true;
for(var i=0,l=array.length-1;i<l;i++)
for(var j=i;j<l+1;j++)
{
if(!array[i].equals(array[j]))
newArray.push(array[i]);
}
We are required to write a JavaScript function that takes in one such array of objects. The function creates and return a new array in which no objects are repeated (by repeated we mean objects having same value for "Country" property.)
Moreover, the function should assign a count property to each object that represents the number of times they appeared in the original array.
const arr = [
{
"Country": "BR",
"New Lv1−Lv2": "#N/A"
},
{
"Country": "BR",
"New Lv1−Lv2": "#N/A"
},
{
"Country": "",
"New Lv1−Lv2": "test"
}];
const convert = (arr) => {
const res = {};
arr.forEach((obj) => {
const key = `${obj.Country}${obj["New Lv1−Lv2"]}`;
if (!res[key]) {
res[key] = { ...obj, count: 0 };
};
res[key].count += 1;
});
return Object.values(res);
};
console.log(convert(arr));
know more
With ES6, one can use Array#reduce with an object to store the counts.
let counts = arr.reduce((acc, curr)=>{
const str = JSON.stringify(curr);
acc[str] = (acc[str] || 0) + 1;
return acc;
}, {});
Demo
To create a new array without duplicates, a Set can be used with Array#filter.
let set = new Set;
let res = arr.filter(x => {
const str = JSON.stringify(x);
return !set.has(str) && set.add(str);
});
Demo

Categories