I had used for loop to iterate nested objects, I am trying to replace forEach with the map function, without success. Can anyone help me with this?
schema.js
const products_schema = {
product_name: {
auto: false,
type: "string",
min: 5,
max: 10,
special_characters: ['_', ' '],
numbers: true,
alphabet: true,
required: true,
correct: ""
},
product_image: {
auto: false,
type: "array:string",
min: 0,
max: 50,
required: true
}
}
const specification_schema = {
brand: {
auto: false,
type: "string",
min: 10,
max: 50,
special_characters: ['_', ' '],
numbers: true,
alphabet: true,
required: true
}
}
let schema = {
products_schema:products_schema,
specification_schema:specification_schema
}
for(var key in schema)
{
var value = schema[key]
Object.keys(value).forEach(key => console.log(value[key].type));
}
"Expected output:"
string
array:string
string
use Object.values then use map to return only type property.
const products_schema = {
product_name: {
auto: false,
type: "string",
min: 5,
max: 10,
special_characters: ['_', ' '],
numbers: true,
alphabet: true,
required: true,
correct: ""
},
product_image: {
auto: false,
type: "array:string",
min: 0,
max: 50,
required: true
}
}
const specification_schema = {
brand: {
auto: false,
type: "string",
min: 10,
max: 50,
special_characters: ['_', ' '],
numbers: true,
alphabet: true,
required: true
}
}
let schema = {
products_schema:products_schema,
specification_schema:specification_schema
}
const mergedObjects = {...products_schema, ...specification_schema};
const output = Object.values(mergedObjects).map(({type}) => type);
console.log(output);
You could use nested Object.values():
const products_schema={product_name:{auto:false,type:"string",min:5,max:10,special_characters:['_',' '],numbers:true,alphabet:true,required:true,correct:""},product_image:{auto:false,type:"array:string",min:0,max:50,required:true}},
specification_schema={brand:{auto:false,type:"string",min:10,max:50,special_characters:['_',' '],numbers:true,alphabet:true,required:true}},
schema={ products_schema, specification_schema }
Object.values(schema).forEach(o => {
Object.values(o).forEach(a => console.log(a.type))
})
If you want to get an array of nested type you could use flatMap
const products_schema={product_name:{auto:false,type:"string",min:5,max:10,special_characters:['_',' '],numbers:true,alphabet:true,required:true,correct:""},product_image:{auto:false,type:"array:string",min:0,max:50,required:true}},
specification_schema={brand:{auto:false,type:"string",min:10,max:50,special_characters:['_',' '],numbers:true,alphabet:true,required:true}},
schema={ products_schema, specification_schema }
const types = Object.values(schema).flatMap(o =>
Object.values(o).map(a => a.type)
)
console.log(types)
If flatMap is not supported, you could simply use the first snippet and push to an array instead of logging it to the console.
const output = [];
Object.values(schema).forEach(o =>
Object.values(o).forEach(a => output.push(a.type))
)
Related
how to get new array newSelect using map ,forEach
const selects = [false, true, true, true, false];
const oldSelects = [
{ select: true, name: 'AA' },
{ select: true, name: 'AA' },
{ select: true, name: 'AA' },
{ select: true, name: 'AA' },
{ select: true, name: 'AA' },
];
const newSelect = [
{ select: false, name: 'AA' },
{ select: true, name: 'AA' },
{ select: true, name: 'AA' },
{ select: true, name: 'AA' },
{ select: false, name: 'AA' },
];
oldSelects[0].select === selects[0]
#Inder answer is great, but a map looks more clean imo:
const selects = [false, true, true, true, false];
const oldSelects = [{
select: true,
name: "AA"
},
{
select: true,
name: "AA"
},
{
select: true,
name: "AA"
},
{
select: true,
name: "AA"
},
{
select: true,
name: "AA"
}
];
const newSelect = oldSelects.map((el, i) => ({
select: selects[i],
name: el.name
}));
console.log(newSelect);
Hey you can map the old array to a new one.
const selects = [false, true, true, true, false];
const oldSelects = [{
select: true,
name: 'AA'
},
{
select: true,
name: 'AA'
},
{
select: true,
name: 'AA'
},
{
select: true,
name: 'AA'
},
{
select: true,
name: 'AA'
},
];
const newSelect = oldSelects.map((object, index) => {
object['select'] = selects[index]
return object;
})
console.log(newSelect)
Using forEach
const selects = [false, true, true, true, false];
const oldSelects = [{
select: true,
name: 'AA'
},
{
select: true,
name: 'AA'
},
{
select: true,
name: 'AA'
},
{
select: true,
name: 'AA'
},
{
select: true,
name: 'AA'
},
];
const newSelects = []
oldSelects.forEach((selectItem, index) => newSelects.push({...selectItem, select: selects[index]}))
console.log(newSelects)
Using map
const selects = [false, true, true, true, false];
const oldSelects = [{
select: true,
name: 'AA'
},
{
select: true,
name: 'AA'
},
{
select: true,
name: 'AA'
},
{
select: true,
name: 'AA'
},
{
select: true,
name: 'AA'
},
];
const newSelects = oldSelects.map((selectItem, index) => ({...selectItem, select: selects[index]}))
console.log(newSelects)
The following is a sample that yields the desired output.
const data = [
{ itemID: '300', status: 'active', inventoryFlag: true, certifiedFlag: false, donateFlag: true },
{ itemID: '400', status: 'inactive', inventoryFlag: true, certifiedFlag: true, donateFlag: false },
{ itemID: '500', status: 'active', inventoryFlag: false, certifiedFlag: false, donateFlag: false },
{ itemID: '600', status: 'active', inventoryFlag: false, certifiedFlag: true, donateFlag: true },
{ itemID: '700', status: 'inactive', inventoryFlag: false, certifiedFlag: true, donateFlag: false }
];
document.getElementById("data").innerText = JSON.stringify(data.filter(o => o.inventoryFlag || o.donateFlag));
<textarea id="data" rows="50" cols="100"></textarea>
I'm trying to find a way to list the filter-by flags in a separate array and then use that in the .filter() somehow to get the same result set as the above code.
For example, here are the flags to use for filtering AND at least one of the values must be true in the object to be included in the final dataset -
const flags = ['inventoryFlag', 'donateFlag'];
As a start, I tried this but it didn't do anything:
const filteredData = data.filter(o => flags.includes(Object.keys(o)));
Inside of the filter, use the some method to detect if any of the property keys of an entry, that are contained in the flags array, have the a value of true.
const data = [
{ itemID: '300', status: 'active', inventoryFlag: true, certifiedFlag: false, donateFlag: true },
{ itemID: '400', status: 'inactive', inventoryFlag: true, certifiedFlag: true, donateFlag: false },
{ itemID: '500', status: 'active', inventoryFlag: false, certifiedFlag: false, donateFlag: false },
{ itemID: '600', status: 'active', inventoryFlag: false, certifiedFlag: true, donateFlag: true },
{ itemID: '700', status: 'inactive', inventoryFlag: false, certifiedFlag: true, donateFlag: false }
];
const flags = ['inventoryFlag', 'donateFlag'];
const result = data.filter(entry =>
flags.some(flag => entry[flag] === true)
);
console.log(result);
I am trying to iterate an dictionary using map. But i could not able to get the nested dictionary properties. For example i need the key where value.type==string.can anyone help me with this?
data.js
const products_schema = {
_id: {
auto: true
},
product_name: {
auto: false,
type: "string",
min: 5,
max: 10,
special_characters: ['_', ' '],
numbers: true,
alphabet: true,
required: true,
correct: ""
},
product_image: {
auto: false,
type: "array:string",
min: 0,
max: 50,
required: true
},
product_specification: {
auto: false,
type: "array:specification_schema",
min: 0,
max: 50,
required: true
}
}
}
let schema=new Map()
schema.set('products_schema',products_schema)
for([key,value] of schema.entries()){
console.log(value.type) //shows undefined in the console
}
The simplest way to iterate this map would be to use Object.keys() as so:
var products_schema = {
_id: {
auto: true
},
product_name: {
auto: false,
type: "string",
min: 5,
max: 10,
special_characters: ['_', ' '],
numbers: true,
alphabet: true,
required: true,
correct: ""
},
product_image: {
auto: false,
type: "array:string",
min: 0,
max: 50,
required: true
},
product_specification: {
auto: false,
type: "array:specification_schema",
min: 0,
max: 50,
required: true
}
}
Object.keys(products_schema).forEach(key => console.log(products_schema[key].type));
I do not know why you need to use the Map object, but for this case of iterating through objects, you can try the good old for..in loop, which iterates through the enumerable properties of your products_schema object.
const products_schema = {
_id: {
auto: true
},
product_name: {
auto: false,
type: "string",
min: 5,
max: 10,
special_characters: ['_', ' '],
numbers: true,
alphabet: true,
required: true,
correct: ""
},
product_image: {
auto: false,
type: "array:string",
min: 0,
max: 50,
required: true
},
product_specification: {
auto: false,
type: "array:specification_schema",
min: 0,
max: 50,
required: true
}
};
for (const key in products_schema){
console.log(key);
for (const inner in products_schema[key]){
console.log(`${inner}:${products_schema[key][inner]}`);
}
}
Using Map() isn't always the best solution, although I have to admit in circumstances where you know the name of the key you want it's great, but to get a birds-eye view of a Map's content is a little more involved.
In the following demo we will use:
objToMap(object): Using Object.entries() and destructure the result within a for...of loop. Each iteration is a simple .set(). A complete Map is returned.
displayMap(Map): Displaying all paths of the Map we'll use two for..of loops. The outer loop will address each key/value of Map. The inner loop will address each key/value of the value extracted from the outer loop.
getPath(Map, root, prop): The second parameter is the Map key (ex. 'product_name'). The third parameter is the key within the object of second parameter (ex. 'type'). Once the second parameter is found with Map.get() a destructuring for...of loop of Map.entries() is filtered by .filter() and the result from Object.fromEntries() is returned.
let products_schema = {
_id: {
auto: true
},
product_name: {
auto: false,
type: "string",
min: 5,
max: 10,
special_characters: ['_', ' '],
numbers: true,
alphabet: true,
required: true,
correct: ""
},
product_image: {
auto: false,
type: "array:string",
min: 0,
max: 50,
required: true
},
product_specification: {
auto: false,
type: "array:specification_schema",
min: 0,
max: 50,
required: true
}
}
function objToMap(obj) {
let map = new Map();
for (let [key, value] of Object.entries(obj)) {
map.set(key, value);
}
return map;
}
let x = objToMap(products_schema);
// Display all map paths
function displayMap(Map) {
for (let [key, value] of Map.entries()) {
for (let [prop, val] of Object.entries(value)) {
console.log(key + ': ' + prop + ': ' + val);
}
}
}
displayMap(x);
function getPath(Map, root, prop) {
let level1 = Map.has(root) ? Map.get(root) : {};
const filtered = Object.entries(level1)
.filter(([key, value]) => key.includes(prop));
return Object.fromEntries(filtered);
}
let y = getPath(x, 'product_name', 'type');
console.log(y);
// if root or prop is not found an empty object is returned
let z = getPath(x, 'product_name', 'foo');
console.log(z);
I am using a Map to match incoming requests. I want to match those requests with their pair as soon as I get them. Order matters because it's first to come, first to match. Avoiding unnecessary operations is a requirement. My understanding is hash maps are faster than arrays iterations, and Maps maintain order. What is the best implementation for matching streaming objects with little to no space or time complexity? The data structure is not set in stone, it can be modified and encoded in whatever format optimizes, as long as the information is not lost. From my understanding, the best that can be achieved is O(n). Another problem I am facing with hashing is overwriting duplicates in the queue. This is what I have.
function* match(items, identity, remaining = new Map()) {
for (let item of items) {
let id = identity(item);
let pair = x =>({type:x.type==="passenger"? "driver": "passenger", direction:x.direction, time:x.time})
let key = item=> item.type + item.direction + item.time;
let candidate = remaining.get(key(pair(id)));
if (candidate) {
remaining.delete(key(pair(id)));
yield [item, candidate];
} else {
remaining.set(key(id), item);
}
}
}
// Example:
let items = [{
type: 'driver',
direction: 'east',
time: '9:15',
name:['Archibald Trump']
},{
type: 'passenger',
direction: 'east',
time: '9:15',
name:['Bacon Eater']
},{
type: 'passenger',
direction: 'east',
time: '9:15',
name:['Banjo Barney']
},{
type: 'passenger',
direction: 'east',
time: '9:15',
name:['Flimsy Stick']
}, {
type: 'passenger',
direction: 'west',
time: '9:30',
name:['Big Red']
},{
type: 'passenger',
direction: 'west',
time: '9:35',
name:['Hathaway Anne']
}];
let remaining = new Map();
let pairs = match(items, item => item, remaining);
console.log('pairs',...pairs);
console.log('remaining',...remaining.values());
Encapsulation & Space Complexity:
Your usage of Set is appropriate, but the code can be improved by encapsulating the matching functionality and getting rid of globals. I suggest a generator which yields matching pairs as follows with reduced space complexity:
// Match items with first equal match:
function* match(items, equals, remaining = new Set()) {
items:
for (let item of items) {
for (let candidate of remaining) {
if (equals(item, candidate)) {
remaining.delete(candidate);
yield [item, candidate];
continue items;
}
}
remaining.add(item);
}
}
// Example:
let items = [1, 2, 5, 3, 3, 4, 2, 1, 4];
let remaining = new Set();
let pairs = match(items, (a, b) => a == b, remaining);
console.log(...pairs);
console.log(...remaining);
Depending on your items, you would need to supply a matching equals callback. In your case:
let pairs = match(
items,
(a, b) =>
a.type !== b.type &&
a.direction === b.direction &&
a.time === b.time,
remaining
);
Optimization:
If you could map requests to primitive identity values, you could replace the for (let i of memo) { ... } loop with a simple map lookup. The time complexity to pair n items then reduces to O(n).
However, since you are not matching 'identical' items but items with opposing type property, this optimization is not directly applicable. You need to add another callback which gives us the expected id of a matching item.
Also, since you might encounter multiple request with identical identity, you need a multimap:
// Multimap insertion:
function insert(map, key, value) {
let values = map.get(key);
if (values) values.push(value);
else map.set(key, [value]);
}
// Multimap retrieval:
function retrieve(map, key) {
let values = map.get(key);
if (values) {
let value = values.pop();
if (values.length === 0) map.delete(key);
return value;
}
}
// Match items with first identical match:
function* match(items, identity, match, remaining) {
for (let item of items) {
let candidate = retrieve(remaining, match(item));
if (candidate) yield [item, candidate];
else insert(remaining, identity(item), item);
}
}
// Example:
let items = [{
type: 'driver',
direction: 'east',
time: '9:15',
name: ['Archibald Trump']
}, {
type: 'passenger',
direction: 'east',
time: '9:15',
name: ['Bacon Eater']
}, {
type: 'passenger',
direction: 'east',
time: '9:15',
name: ['Banjo Barney']
}, {
type: 'passenger',
direction: 'east',
time: '9:15',
name: ['Flimsy Stick']
}, {
type: 'passenger',
direction: 'west',
time: '9:30',
name: ['Big Red']
}, {
type: 'passenger',
direction: 'west',
time: '9:35',
name: ['Hathaway Anne']
}];
let remaining = new Map();
let pairs = match(
items,
item => '' + (item.type == 'driver') + item.direction + item.time,
item => '' + (item.type == 'passenger') + item.direction + item.time,
remaining
);
console.log(...pairs);
console.log(...remaining.values());
The runtime complexity of above implementation is not easily determined as it depends on the runtime complexity of Array.shift() and Array.push(). However, if we assume that such key collisions are rare or assume that the JavaScript engine executed both of these methods in amortized constant time, we could still expect an O(n) runtime complexity for n items.
Maps are faster than arrays. You can access an map key much quicker than looping over an array every time. Here is your example using an map.
var pairs = [];
var memo = {};
function pair(item) {
var key = item.type.toString() + item.direction + item.time;
if(memo[key]) {
pairs.push(item);
delete memo[key];
} else {
memo[key] = item;
}
}
var ar = [{
type: true,
direction: false,
time: '9:00'
}, {
type: false,
direction: false,
time: '9:00'
}, {
type: true,
direction: false,
time: '9:00'
}, {
type: false,
direction: false,
time: '9:00'
}, {
type: true,
direction: false,
time: '9:00'
}, {
type: false,
direction: false,
time: '9:00'
}, {
type: true,
direction: false,
time: '9:00'
}, {
type: false,
direction: false,
time: '9:00'
}, {
type: true,
direction: false,
time: '9:00'
}, {
type: false,
direction: false,
time: '9:00'
}, {
type: true,
direction: false,
time: '9:00'
}, {
type: false,
direction: false,
time: '9:00'
}, {
type: false,
direction: false,
time: '9:00'
}, {
type: false,
direction: false,
time: '9:00'
}, {
type: false,
direction: false,
time: '9:00'
}, {
type: false,
direction: false,
time: '9:00'
}, {
type: false,
direction: false,
time: '9:00'
}, {
type: false,
direction: false,
time: '9:00'
}, {
type: false,
direction: false,
time: '9:00'
}, {
type: false,
direction: false,
time: '9:00'
}, {
type: false,
direction: false,
time: '9:00'
}, {
type: false,
direction: false,
time: '9:00'
}];
for (let it of ar) {
pair(it);
}
console.log('matching pairs: ', pairs);
console.log('left over nonmatching pairs:', Object.values(memo));
I try to connect several range slider from: http://ionden.com/a/plugins/ion.rangeSlider/en.html so that the end of the first slider is automatically recognized as the fix start of the second and so on. Furthermore this should be updated on the fly. My current code works only partially - connection works (even it is not fixed), but the real time update is not working.
Attached the code:
from = 0,
to = 0;
from2 = 0,
to2 = 0;
var saveResult = function (data) {
from = data.from;
to = data.to;
};
var writeResult = function () {
var result = from;
$result.html(result);
};
var saveResult2 = function (data) {
from2 = data.from;
to2 = data.to;
};
var writeResult2 = function () {
var result2 = from2;
$result.html(result);
};
$("#select-length").ionRangeSlider({
hide_min_max: true,
keyboard: true,
min: 0,
max: 20,
from: 0,
to: 10,
type: 'double',
step: 0.25,
prefix: "",
grid: true,
onStart: function (data) {
saveResult(data);
writeResult();
},
onChange: function(data){
saveResult(data);
writeResult();
},
onChange: saveResult,
onFinish: saveResult
});
$("#select-length2").ionRangeSlider({
hide_min_max: true,
keyboard: true,
min: 0,
max: 20.16,
from: to,
to: 12,
type: 'double',
step: 0.25,
prefix: "",
grid: true,
onStart: function (data) {
saveResult2(data);
writeResult2();
},
onChange: function(data){
saveResult2(data);
writeResult2();
},
onChange: saveResult2,
onFinish: saveResult2
});
$("#select-length3").ionRangeSlider({
hide_min_max: true,
keyboard: true,
min: from2,
max: 20.16,
from: 12,
to: 12,
type: 'double',
step: 0.25,
prefix: "",
grid: true
});
Ion.RangeSlider realtime update is doing this way: http://jsfiddle.net/IonDen/4k3d4y3s/
var $range1 = $(".js-range-slider-1"),
$range2 = $(".js-range-slider-2"),
range_instance_1,
range_instance_2;
$range1.ionRangeSlider({
type: "single",
min: 100,
max: 1000,
from: 500,
onChange: function (data) {
range_instance_2.update({
from: data.from
});
}
});
range_instance_1 = $range1.data("ionRangeSlider");
$range2.ionRangeSlider({
type: "single",
min: 100,
max: 1000,
from: 500,
onChange: function (data) {
range_instance_1.update({
from: data.from
});
}
});
range_instance_2 = $range2.data("ionRangeSlider");