I need some dummy data that I can use. I usually, manually create my data in a variable like...
const jsonData = [
{
name: 'random',
age: '0',
}
];
I'm trying to create a function that gives me back an array with a list of objects in (like the above) the amount of objects in the array is based on the value I give it.
I came to the conclusion using the map function would be best, like so:
const myMap = new Map();
myMap.forEach((q, n) => {
});
I'm still learning. Honestly now sure how I'd go about creating this.
You can use a simple loop:
function genData(n) {
var results = [];
for (var i = 0; i < n; i++) {
results.push({name: 'random', age: 0});
}
return results;
}
If you want to randomize the property values, look into Math.random.
Here is a simple example that picks a random value from provided lists:
function genData(n, values) {
var results = [];
for (var i = 0; i < n; i++) {
var obj = {};
for (var prop in values) {
obj[prop] = values[prop][Math.floor(Math.random() * values[prop].length)];
results.push(obj);
}
}
return results;
}
console.log(genData(3, {name: ['foo', 'bar', 'baz'], age: [0, 10, 20, 30, 40]}));
Related
I have an array of objects that looks something like (rough example):
[{id:1, stuff:moreStuff}, {id:6, manyStuff,Stuffing}, {id:4, yayStuff, stuff}, {id:6, manyStuff, Stuffing}]
The problem is that in the array, there are several duplicate objects. The current solution I've thought of so far is something along the lines of this:
const DuplicateCheck = []
const FinalResult = []
for (let i = 0; i < ArrayOfObjects.length; i++) {
let isPresent = false;
for (let j = 0; j < duplicateCheck.length; j++) {
if (ArrayOfObjects[i].id == duplicateCheck[j]) {
isPresent = true;
}
}
if (isPresent = false) {
DuplicateCheck.push(ArrayOfObjects[i].id
FinalResult.push(ArrayOfObjects[i]
}
}
Now after learning big O, it seems like this is a very inefficient way to go about doing this problem. So my question is, is there a better, more efficient way to solve this problem?
Yes, use a Set for your DuplicateCheck which gives you O(1) access by id:
const duplicateCheck = new Set
const finalResult = []
for (const object of arrayOfObjects) {
if (!duplicateCheck.has(object.id)) {
duplicateCheck.add(object.id)
finalResult.push(object)
}
}
You could iterate over the array and store the id in and object (hash table) and then check if exist. Something like:
const DuplicateCheck = {}
const FinalResult = []
for (let i = 0; i < ArrayOfObjects.length; i++) {
let currentId = ArrayOfObjects[i].id
if (!DuplicateCheck[currentId]) {
DuplicateCheck[currentId] = 1
FinalResult.push(ArrayOfObjects[i])
}
}
And you will receive all unique objects in the FinalResult
You could keep usedIds as object properties and add to the filtered array only if the object has no such property or just add your items in Set if that's a possibility for you. Set as a data structure can only store non-duplicates.
Without Set:
const filteredArray = [];
const usedIds = {};
for (const item of array) {
if (!usedIds[item.id]) {
usedIds[item.id] = true;
filteredArray.push(item);
}
}
With Set:
const filteredArray = [];
const usedIds = new Set();
for (const item of array) {
if (!usedIds.has(item.id)) {
usedIds.add(item.id);
filteredArray.push(item);
}
}
Runnable example:
const array = [
{
id: 1,
stuff: 'stuff',
moreStuff: 'moreStuff'
},
{
id: 6,
manyStuff: 'manyStuff',
stuffing: 'stuffing'
},
{
id: 4,
yayStuff: 'yayStuff',
stuff: 'stuff'
},
{
id: 6,
manyStuff: 'manyStuff',
stuffing: 'stuffing'
}
];
const filteredArray = [];
const usedIds = {};
for (const item of array) {
if (!usedIds[item.id]) {
usedIds[item.id] = true;
filteredArray.push(item);
}
}
console.log(filteredArray);
You can also use a Map to filter out duplicates. Contrary to the Set approach by Bergi this solution leaves the last version of the duplicate, since it overrides the key/value-pair with the same key.
const objectsById = new Map(arrayOfObjects.map(object => [object.id, object]));
const finalResult = Array.from(objectsById.values());
The code above does need to iterate the collection 2 times. Once using map to create key/value-pairs and once when the created array is converted to a Map.
When the resulting objectsById is created we'll have to iterate over the values to convert them back to array.
In total this means between 2 and 3 iterations over the full collection, which more often then not still a lot faster then solutions using find. Since that iterates over the array every time it is called.
You can reduce the amount of iterations by 1 if you omit the map call and manually insert the elements in objectsById:
const objectsById = new Map();
for (const object of arrayOfObjects) {
objectsById.set(object.id, object);
}
I have an array of exam result, it contains the date the exam was sat and the grade achieved. I want to put all the grades in one array and the dates in another so I can plot them in a chart.js application. How can I separte them?
Results Array example layout:
Results{
[0] {examDate: "2017-10-16T10:30:00", <ResultEntry>grade: A}
[1] {examDate: "2017-15-16T11:00:00", <ResultEntry>grade: C}
[2] {examDate: "2017-16-16T11:30:00", <ResultEntry>grade: B}
[3]{examDate: "2017-20-16T12:00:00", <ResultEntry>grade: B}
}
But what I try doesn't populate the two new arrays
var dateArray;
var gradeArray;
var counter = 0;
for (members in results) {
dateArray[counter] = members[0];
gradeArray[counter] = members[1];
counter++;//increment storage index
}
I have Jquery installed on my project can the .each functionality be used to achieve this?
You can use map method by passing a callback function.
The map() method creates a new array with the results of calling a provided function(callback) on every element in the calling array.
let results=[{examDate: "2017-10-16T10:30:00", grade: 'A'},{examDate: "2017-15-16T11:00:00", grade: 'C'},{examDate: "2017-16-16T11:30:00", grade: 'B'},{examDate: "2017-20-16T12:00:00", grade: 'B'}];
let dates=results.map(function(a){
return a.examDate;
});
let grades=results.map(function(a){
return a.grade;
});
console.log(dates);
console.log(grades);
You can use also arrow functions.
let grades=results.map(a => a.grade);
You need to get values of fields from array elements. Check this:
var dateArray = [];
var gradeArray = [];
var counter = 0;
for (var member in results) {
dateArray.push(member.examDate);
gradeArray.push(member.grade);
}
If results is an array, then in this line
for (members in results) {
members is basically the index value 0,1,..
so members[0] will be undefined
I have Jquery installed on my project can the .each functionality be
used to achieve this?
Yes, but why not use the native forEach instead
var dateArray = [], gradeArray = [];
results.forEach( function( result ){
dateArray.push( result.examDate );
gradeArray.push( result.grade );
});
Considering that the results array is has the following shape:
let results = [
{ examDate: "2017-10-16T10:30:00", grade: 'A' },
{ examDate: "2017-15-16T11:00:00", grade: 'C' },
{ examDate: "2017-16-16T11:30:00", grade: 'B' },
{ examDate: "2017-20-16T12:00:00", grade: 'B' }
];
Array.prototype.map is perfect for this purpose:
let dateArray = results.map(result => result.examDate);
let gradeArray = results.map(result => result.grade);
You can also loop over the elements in a few different ways:
let dateArray = [],
gradeArray = [];
for (let result of results) {
dateArray.push(result.examDate);
gradeArray.push(result.grade);
}
And a solution similar to yours:
var dateArray = [],
gradeArray = [];
for (var i = 0; i < results.length; i++) {
dateArray[i] = results[i].examDate;
gradeArray[i] = results[i].grade;
}
You can also push them into the array instead of setting a position to the value:
var dateArray = [],
gradeArray = [];
for (var i = 0; i < results.length; i++) {
dateArray.push(results[i].examDate);
gradeArray.push(results[i].grade);
}
And using jQuery each as you mention:
var dateArray = [],
gradeArray = [];
$.each(results , function(i, value) {
dateArray.push(value.examDate);
gradeArray.push(value.grade);
});
sorry, i m a beginner in javascript.
Can someone explain me how to modify this Object
{toto:[12,13,15],titi:[45,12,34]}
to this Array
newArray = [
{
toto:12,
titi:45
},{
toto:13,
titi:12
},{
toto:15,
titi:34}
]
Also, what the solution if the toto and titi doesn't have the same lenght
Thanks for support!
Here's how I did it. In this way, you don't need to know the names of the keys or the size of the array, but it does require a few loops.
obj = {toto:[12,13,15],titi:[45,12,34]};
newArray = [];
// Find the longest array in your data set
longest = 0;
Object.keys(obj).forEach(function(key) {
if (obj[key].length > longest) {
longest = obj[key].length;
}
});
// Loop through the existing data set to create new objects
for (i = 0; i<longest; i++) {
newObject = {};
Object.keys(obj).forEach(function(key) {
newObject[key] = obj[key][i];
});
newArray.push(newObject);
}
console.log(newArray);
plnkr.co demo in the script.js file.
If you want to ignore keys that would have undefined values for uneven loops, you can add a conditional inside the forEach loop that creates a new object:
Object.keys(obj).forEach(function(key) {
if (obj[key][i] !== undefined) {
newObject[key] = obj[key][i];
}
});
Assuming lengths of toto and titi are the same:
Obj = {toto:[12,13,15],titi:[45,12,34]};
newArray = [];
for (var k in Obj["toto"]) {
newArray.push({ toto:Obj["toto"][k],titi:Obj["titi"][k] });
}
Since the lengths of your inner arrays are equal, you should be able to simply loop through them and add a value from each array (for each iteration) into a new array :
// Your input
var input = {toto:[12,13,15],titi:[45,12,34]};
// An array to store your output
var output = [];
// Since your inner arrays are of equal size, you can loop through them
// as follows
for(var i = 0; i < input.toto.length; i++){
output.push({ toto: input.toto[i], titi: input.titi[i]});
}
You can see a working example of this here and what the output array looks like below :
A more generic approach
var object = { toto: [12, 13, 15], titi: [45, 12, 34] },
newArray = function (o) {
var keys = Object.keys(o),
l = keys.reduce(function (r, a) { return Math.max(r, o[a].length); }, 0),
i = 0,
t,
result = [];
while (i < l) {
t = {};
keys.forEach(function (k) { t[k] = o[k][i]; });
result.push(t);
i++;
}
return result;
}(object);
document.write('<pre>' + JSON.stringify(newArray, 0, 4) + '</pre>');
I have demonstrated my problem in a fiddle: http://jsfiddle.net/sljux/zVg7R/3/
I have an array of objects. For simplicity, lets say each object has a name, and an array of values, all observable:
self.array = [
{
name: ko.observable("first"),
values: ko.observableArray([1, 2, 3])
},
{
name: ko.observable("second"),
values: ko.observableArray([2, 3, 4])
},
{
name: ko.observable("third"),
values: ko.observableArray([3, 4, 5])
}
];
From that array I need to filter out certain objects, and add an additional computed to each one, which computes the sum of all values. The filtering part isn't important to the problem, so it won't be done. The problem is that the observable needs to be a property of each object, and it needs to reference that object's values array.
My best try was:
self.newArray = ko.observableArray([]);
for(var i = 0; i < self.array.length; i++) {
var obj = {
name: ko.observable("new " + self.array[i].name()),
values: ko.observableArray(self.array[i].values())
};
obj.sum = ko.computed({
read: function() {
var res = 0;
for (var j = 0; j < obj.values().length; j++)
res += obj.values()[j];
return res;
},
owner: obj
});
self.newArray.push(obj);
}
The problem is that the reference to the values observable array is somehow lost. That is, on the first computing, each object gets the sum of his values, but in the end, each computed computes the sum of the last object in array.
I tried with, and without the owner part of the computed, the reference is still transferred. The bug is obviously visible in the fiddle, where I have set up three buttons that change each values array.
I also tried setting it up as a class:
function Obj(name, values) {
...
}
self.newArray.push(new Obj("first", [1, 2, 3]);
but the same thing happens.
Sort answer: use ko.utils.arrayForEach instead of the manual for loop:
ko.utils.arrayForEach(self.array, function(item) {
var obj = {
name: ko.observable("new " + item.name()),
values: ko.observableArray(item.values())
};
obj.sum = ko.computed({
read: function() {
var res = 0;
for (var j = 0; j < obj.values().length; j++)
res += obj.values()[j];
return res;
},
owner: obj
});
self.newArray.push(obj);
});
Demo JSFiddle.
Long answer: you've bitten by the fact that in JavaScript the variables are function scoped so your for loop it does not create three local obj variable but reuses the same one variable and this combined with how closures work you will end up with all your computed referencing the last value:
You can solve this with wrapping the for body in an immediately executed function:
for(var i = 0; i < self.array.length; i++) {
(function(){
var obj = {
name: ko.observable("new " + self.array[i].name()),
values: ko.observableArray(self.array[i].values())
};
obj.sum = ko.computed({
read: function() {
var res = 0;
for (var j = 0; j < obj.values().length; j++)
res += obj.values()[j];
return res;
},
owner: obj
});
self.newArray.push(obj);
})();
}
Demo JSFiddle.
I have a data dictionary like this:
var data = {
'text1': 1,
'text2': 2,
'text3': 3,
...
'text20': 20
];
I need to pick a random selection of those keys and then shuffle it's values. In the example, it should write something like this:
> console.log(choose(data, 5));
[ { key: 'text15', value: 8 },
{ key: 'text6', value: 3 },
{ key: 'text3', value: 15 },
{ key: 'text19', value: 6 },
{ key: 'text8', value: 19 } ]
For now I'm extracting the keys into another array and sorting by Math.random() but I'm stuck at swaping the values because no key should have the same value it initially had.
How would you swap key/values here?
Thanks
I put together a possible solution using underscore.js to simplify traversing the object and arrays in a cross browser manner:
var data = {
text1: 1,
text2: 2,
text3: 3,
text4: 4,
text5: 5,
text6: 6,
text7: 7,
text8: 8,
text9: 9,
text10: 10
};
function choose(data, num)
{
var keys = _.sortBy(
_.keys(data),
function(k)
{
return (Math.random() * 3) - 1;
}
),
results = [],
k1, k2;
if (num > keys.length) {
throw new Error('Impossible to retrieve more values than exist');
}
while (results.length < num) {
k1 = k2 || keys.pop();
k2 = keys.pop();
results.push({key:k1, value: data[k2]});
}
return results;
}
console.log(choose(data, 5));
This isn't necessarily an optimal approach but it seems to meet your requirements. I first grab all of the keys and sort them randomly. I then loop through the random keys creating a new object with one key and the following keys value. That way you'll always end up with a different value associated with each key. If you need it to work when the value of num passed in to the function == the number of keys in the data then you'll have to add a little more code - I'll leave that as an exercise for the reader :)
You can have a play with this code on jsfiddle:
http://jsfiddle.net/zVyQW/1/
You could do this:
collect names and corresponding values in two arrays names and values
shuffle both arrays independently of each other
take the first n items of both arrays and combine them
Here’s an example implementation:
Array.prototype.shuffle = function() {
for (var i=this.length-1, j, tmp; i>0; i--) {
j = Math.round(Math.random()*i);
tmp = this[i], this[i] = this[j], this[j] = tmp;
}
return this;
};
function choose(data, number) {
var names = [], values = [], pick = [];
for (var name in data) {
if (data.hasOwnProperty(name)) {
names.push(name);
values.push(data[name]);
}
}
names = names.shuffle(), values = values.shuffle();
for (var i=Math.min(number >>> 0, names.length-1); i>=0; i--) {
pick.push({key: names[i], value: values[i]});
}
return pick;
}
Been a while since this was answered, but I was working on shuffling and found the following to be by far the fastest implementation with an evenly random distribution.
It's fast because it only makes one call to Math.random on each iteration, all the rest is done by property access. It doesn't modify the array, just reassigns values.
function shuffle(a) {
var t, j, i=a.length, rand=Math.random;
// For each element in the array, swap it with a random
// element (which might be itself)
while (i--) {
k = rand()*(i+1)|0;
t = a[k];
a[k]=a[i];
a[i]=t;
}
return a;
}
It uses a combination of three functions (including the Array shuffle prototype method).
Here is the complete code:
var obj = {
"red":"RED",
"blue":"BLUE",
"green":"GREEN",
"yellow":"YELLOW",
"purple":"PURPLE"
};
Array.prototype.shuffle = function(){
for (var i = 0; i < this.length; i++){
var a = this[i];
var b = Math.floor(Math.random() * this.length);
this[i] = this[b];
this[b] = a;
}
}
obj = shuffleProperties(obj); // run shuffle
function shuffleProperties(obj) {
var new_obj = {};
var keys = getKeys(obj);
keys.shuffle();
for (var key in keys){
if (key == "shuffle") continue; // skip our prototype method
new_obj[keys[key]] = obj[keys[key]];
}
return new_obj;
}
function getKeys(obj){
var arr = new Array();
for (var key in obj)
arr.push(key);
return arr;
}
for(key in obj){
alert(key);
}
Check all post,
Best Regards.
Use an implementation of random that randomizes a discrete set of values, such as Math.rand seen here. For each index, randomize Math.rand(index, length-1) to get a list of random indexes, the location off all indices will change.