I am trying to get the key from the value of the Object. I have the following array:
["Test 91", "Test 92", "Demo 1", "Demo 2"]
And I have one object:
{
D123_EMG: {
value: "Test 91",
isArchived: true
}
D21: {
value: "Test 92",
isArchived: false
}
Z6200_EMO: {
value: "Demo 1",
isArchived: true
}
G211_GTH: {
value: "Demo 2",
isArchived: false
}
}
So how can I get key as D123_EMG if the value is Test 91?
I tried this, but not getting proper response
var data = Object.keys(objectData);
var keys = []
for(var i = 0; i < array.length; i++){
for(var j = 0; j < data.length; j++){
if(array[i] === objectData[data[j].value) {
keys.push(objectData[data[j])
}
}
}
Also, can it be optimized since I used two loops or one-liner approach?
You can use filter() in this way:
const values = ["Test 91", "Test 92", "Demo 1", "Demo 2"];
const data = {
D123_EMG: {
value: "Test 91",
isArchived: true
},
D21: {
value: "Test 92",
isArchived: false
},
Z6200_EMO: {
value: "Demo 1",
isArchived: true
},
G211_GTH: {
value: "Demo 2",
isArchived: false
}
}
const keysFound = Object.keys(data).filter(key => values.includes(data[key].value));
console.log(keysFound); // ["D123_EMG", "D21", "Z6200_EMO", "G211_GTH"];
This isn't really related to react. Someone else may have a cleaner solution, but here is one that will work if I understand your question correctly:
let data = {
D123_EMG: {
value: "Test 91",
isArchived: true
},
D21: {
value: "Test 92",
isArchived: false
},
Z6200_EMO: {
value: "Demo 1",
isArchived: true
},
G211_GTH: {
value: "Demo 2",
isArchived: false
}
}
let name = '';
Object.entries(data).forEach((v) => {
// if the object value matches, set the name variable to the key
if (v[1].value == 'Test 91') {
name = v[0];
}
})
console.log(name)
I like to use .reduce() which in this case also works. Read from the MDN documentation:
The reduce() method executes a reducer function (that you provide) on each element of the array, resulting in a single output value.
And you can combine it with Object.entries() where the documentation states:
The Object.entries() method returns an array of a given object's own enumerable string-keyed property [key, value] pairs, in the same order as that provided by a for...in loop. (The only important difference is that a for...in loop enumerates properties in the prototype chain as well).
See the working solution what I made:
const data = { D123_EMG: { value: "Test 91", isArchived: true }, D21: { value: "Test 92", isArchived: false }, Z6200_EMO: { value: "Demo 1", isArchived: true }, G211_GTH: { value: "Demo 2", isArchived: false } };
const filterValue = 'Test 91';
const entries = Object.entries(data);
const result = entries.reduce((a, c) => c[1].value === filterValue ? c[0] : a, '');
console.log(result);
I hope this helps!
If you're experiencing this problem in a state management store, then this is a sign that the store is not properly designed. Without more information, I can't really recommend an improvement on how to redesign your state.
So, barring a redesign of your state, you may consider creating a map by value like so:
const byValue = Object.keys(data).reduce((accumulator, currentKey) => {
const currentObject = data[currentKey];
currentObject.key = currentKey;
accumulator[currentObject.value] = currentObject;
return accumulator;
}, {});
This produces a map that looks like this:
{
"Test 91": { "value": "Test 91", "isArchived": true, "key": "D123_EMG" },
"Test 92": { "value": "Test 92", "isArchived": false, "key": "D21" },
"Demo 1": { "value": "Demo 1", "isArchived": true, "key": "Z6200_EMO" },
"Demo 2": { "value": "Demo 2", "isArchived": false, "key": "G211_GTH" }
}
With this, you use the value as the lookup key:
const test91 = byValue["Test 91"]
...
Related
I have an object which contains questions with different types multiple, single and text.
const data = {
questions: [
{
"question": "Question 1",
"value": [
"value_1.1.1",
"value_1.1.2"
],
"type": "multiple",
"options": [
{
"value": "value_1.1.1",
"label": "Value 1.1.1"
},
{
"textValue":"Additional text value",
"value": "value_1.1.2",
"label": "Value 1.1.2"
},
{
"value":"value_1.1.3",
"label":"Value 1.1.3",
}
]
},
{
"question": "Question 2",
"value": "value_2.1.1",
"type": "single",
"options": [
{
"value": "value_2.1.1",
"label": "Value 2.1.1"
},
{
"value": "value_2.1.2",
"label": "Value 2.1.2"
},
]
},
{
"question":"Question 3",
"textValue":"Test 12345",
"type":"text"
}
]
}
I want to create a new array with objects, which contains the question key and the value key.
The value key must contain the label of the selected options.
For a multiple type, the value can contain multiple labels.
The selected option can be retrieved from the parent value key, if it is equal to the value of the option, I want to use the label of this option as value.
In some cases an option also contains a textValue (see 1.1.3), then this must also be added to the value.
So the new array should look like this for the example above:
const newData = [
{
question: "Question 1",
value: ['Value 1.1.1', 'Value 1.1.2', 'Additional text value']
},
{
question: "Question 2",
value: ['Value 2.1.1']
},
{
question: "Question 3",
value: ['Test 12345']
}
];
Well basically loop over the questions, handling each by its own type. The tricky part is the type: multiple but it is managable.
Update: Fixed according to comment
const data = {questions:[{question:"Question 1",value:["value_1.1.1","value_1.1.2"],type:"multiple",options:[{value:"value_1.1.1",label:"Value 1.1.1"},{value:"value_1.1.2",label:"Value 1.1.2"},{textValue:"test12",value:"value_1.1.3",label:"Value 1.1.3"}]},{question:"Question 2",value:"value_2.1.1",type:"single",options:[{value:"value_2.1.1",label:"Value 2.1.1"},{value:"value_2.1.2",label:"Value 2.1.2"},]},{question:"Question 3",textValue:"Test 12345",type:"text"}]};
function get_option_label(options, value) {
return options.find(item => item.value == value).label || value
}
const newData = [];
data.questions.forEach(function(obj) {
var new_obj = {
question: obj.question
}
if (obj.type == "multiple") {
new_obj.value = JSON.parse(JSON.stringify(obj.value))
new_obj.value = new_obj.value.map(item => get_option_label(obj.options, item))
// add textValue for multiple question
// but only if its value is on parent
var objText = obj.options.find((item) => item.textValue);
if (objText && obj.value.indexOf(objText.value) >= 0) {
new_obj.value.push(objText.textValue)
}
}
if (obj.type == "single") {
new_obj.value = [get_option_label(obj.options, obj.value)]
}
if (obj.type == "text") {
new_obj.value = [obj.textValue]
}
newData.push(new_obj)
})
// now replacing all values with labels
console.log(newData);
.as-console-wrapper {
max-height: 100% !important;
top: 0
}
I'm trying to create an array from items inside objects, as well as items inside arrays inside objects in a vue app, by using foreach to loop over them. It works well when I only have one single item, but I can't figure out how to loop over an array inside the object and add all of those items to the array I'm creating.
What I have now
const examples = [
{
name: "Example 1",
type: ["Meat", "Water", "Dairy"],
showDetail: false
},
{
name: "Example 2",
type: Fruit,
showDetail: false
},
{
name: "Example 3",
type: Vegetable,
showDetail: false
}
]
new Vue({
data: {
examplesList: examples,
type: ''
},
methods: {
filterList: function() {
this.type = event.target.value;
}
},
computed: {
uniqueList: function() {
const types = [];
this.examplesList.forEach((example) => {
if (!types.includes(example.type)) {
types.push(example.type);
}
});
return types;
}
}
})
It works fine if I remove the object with the array inside of "type", and adds the Fruit and Vegetable items to the array. Any ideas?
Desired output:
["Meat", "Water", "Dairy", "Fruit", "Vegetable"]
Here is one possible solution. You'll need to translate the solution to vue, of course, but the problem here really doesn't have anything to do with vue specifically so I've shown a vanilla javascript solution just to keep things simple.
const examples = [
{
name: "Example 1",
type: ["Meat", "Water", "Dairy", "Fruit"],
showDetail: false
},
{
name: "Example 2",
type: "Fruit",
showDetail: false
},
{
name: "Example 3",
type: "Vegetable",
showDetail: false
}
];
const types = [];
examples.forEach((example) => {
const exampleTypes = Array.isArray(example.type)
? example.type
: [example.type];
for (let exampleType of exampleTypes) {
if (!types.includes(exampleType)) {
types.push(exampleType);
}
}
});
console.log(types);
Here's an abstract way of doing that using a Set. Sets guarantee unique values meaning there's no need to check if an item is present or not.
Using just an array will become increasingly expensive to check if an item was already added as it will have to scan the entire array for each includes, O(n) time complexity.
const examples = [{
name: "Example 1",
type: ["Meat", "Water", "Dairy"],
showDetail: false
},
{
name: "Example 2",
type: "Fruit",
showDetail: false
},
{
name: "Example 3",
type: "Vegetable",
showDetail: false
}
];
const typeSet = new Set();
let types;
examples.forEach((example) => {
if (Array.isArray(example.type)) {
example.type.forEach(type => {
typeSet.add(type);
});
} else {
typeSet.add(example.type);
}
});
types = [...typeSet];
console.log(types);
Here is one possible solution to achieve the desired result:
computed: {
uniqueList: function() {
return this.examplesList.reduce(
(acc, itm) => (
Array.isArray(itm.type)
? itm.type.filter(t => !acc.includes(t)).length > 0
? [
...acc,
...itm.type.filter(t => !acc.includes(t))
]
: acc
: acc.includes(itm.type)
? acc
: [...acc, itm.type]
), []
)
}
}
Explanation
reduce is used on the array this.examplesList
Each item itm is processed and acc is the accumulator/aggregator (initially set to an empty array [])
if itm.type is an Array, then
if any elements in itm.type array is not already present in acc array, include it (by using the ... spread operator)
otherwise (ie, itm.type is a string)
if it is not already in acc, then include it (again, using ... spread operator)
That's it !
Please comment if any further clarification/s or question/s.
Code snippet
const examples = [{
name: "Example 1",
type: ["Meat", "Water", "Dairy"],
showDetail: false
},
{
name: "Example 2",
type: "Fruit",
showDetail: false
},
{
name: "Example 3",
type: "Vegetable",
showDetail: false
}
];
const getUniqueTypes = (arr = examples) => (
arr.reduce(
(acc, itm) => (
Array.isArray(itm.type)
? itm.type.filter(t => !acc.includes(t)).length > 0
? [
...acc,
...itm.type.filter(t => !acc.includes(t))
]
: acc
: acc.includes(itm.type)
? acc
: [...acc, itm.type]
), []
)
);
console.log(getUniqueTypes());
Working Demo :
const examples = [{
name: "Example 1",
type: ["Meat", "Water", "Dairy"],
showDetail: false
},
{
name: "Example 2",
type: "Fruit",
showDetail: false
},
{
name: "Example 3",
type: "Vegetable",
showDetail: false
}];
let newArray = []
examples.forEach((item) => {
if (typeof(item.type) === 'object') {
item.type.forEach((elem) => {
newArray.push(elem)
})
} else {
newArray.push(item.type)
}
})
console.log(newArray)
In Javascript, how to retrieve an object in an array by one of its property ?
Hi all,
let's assume that we have the below :
"Attributes":[
{
"Name":"Brief",
"Value":"This skirt was fabriced from ...."
},
{
"Name":"Details",
"Value":"Measurements and Pictures are real"
},
{
"Name":"SKUNumber",
"Value":"12345678"
}
]
What I need to do is to get the value of "Value" based on "Name"..
For example :
console.log(Attributes.Brief) ==> "This skirt was fabriced from ...."
So I need a function to help doing that
Note that I don't want to use the index of the object, because its order may changed.
Thank you
Well, it's always better to show what you have attempted rather than just asking..
You can use Array.find to achieve this
let Attributes = [
{
"Name":"Brief",
"Value":"This skirt was fabriced from ...."
},
{
"Name":"Details",
"Value":"Measurements and Pictures are real"
},
{
"Name":"SKUNumber",
"Value":"12345678"
}
]
function getValueByName(name) {
return Attributes.find(d => d.Name.toLowerCase() == name.toLowerCase()).Value
}
console.log(getValueByName('Brief'))
console.log(getValueByName('details'))
console.log(getValueByName('SKUNumber'))
One option you have is to use Array.prototype.filter:
const d = [{
"Name": "Brief",
"Value": "This skirt was fabriced from ...."
},
{
"Name": "Details",
"Value": "Measurements and Pictures are real"
},
{
"Name": "SKUNumber",
"Value": "12345678"
}
]
console.log(d.filter(x=>x.Name==="Brief")[0].Value)
You can also make it more generic:
const d = [{
"Name": "Brief",
"Value": "This skirt was fabriced from ...."
},
{
"Name": "Details",
"Value": "Measurements and Pictures are real"
},
{
"Name": "SKUNumber",
"Value": "12345678"
}
]
const getValOfXfromArrByValOfY = (arr, x, y, val) => arr.find(z => z[y] === val)[x]
console.log(getValOfXfromArrByValOfY(d, 'Value', 'Name', 'SKUNumber'))
You could use a Proxy with a getter for the key, which returns a find of the object with the value.
var object = { attributes: [{ Name: "Brief", Value: "This skirt was fabriced from ...." }, { Name: "Details", Value: "Measurements and Pictures are real" }, { Name: "SKUNumber", Value: "12345678" }] },
attributes = new Proxy(
object.attributes,
{ get: (array, prop) => (array.find(({ Name }) => Name === prop) || {}).Value }
);
console.log(attributes.Brief);
console.log(attributes.SKUNumber);
You can use javascript find function see https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/find see bellow sample code:
var Attributes =[
{
"Name":"Brief",
"Value":"This skirt was fabriced from ...."
},
{
"Name":"Details",
"Value":"Measurements and Pictures are real"
},
{
"Name":"SKUNumber",
"Value":"12345678"
}
]
var found = Attributes.find(function(element) {
return element.Name == "Details";
});
console.log(found.Value); //output : Measurements and Pictures are real
I have some code that will return me the name of the subcat clicked.
Here is the data below:
theData = {
"categories": [
{
"id": "661",
"name": "some name",
"description": "some description",
"subcat": [
{
"id": "662",
"name": "sub 1",
"translations": null
},
{
"id": "663",
"name": "sub 2",
"translations": null
}
],
"image": null
},
{
"id": "657",
"name": "some other name",
"description": "",
"subcat": [
{
"id": "456",
"name": "sub 12",
"translations": null
},
{
"id": "656",
"name": "sub 15",
"translations": null
}
],
"image": null
}
]
};
I need some way to find the parent id of the subcat name.
For example if I gave it "sub 15", it would return "661" which is the parent id
How can I do this?
There's no way by default to access the "parent" of an object in Javascript -- it could be referenced in any number of other objects, or even by itself, so it's not possible to determine what the sole parent of an object is.
Instead, we'll just iterate through all the data until we find the matching id, and return null if we never find it. This solution counts on your IDs being unique entities, so if that's not the case, it'll have to be changed. With that said, here's an example:
function getParent(subID) {
for (var i in theData.categories) {
var parent = theData.categories[i];
if ('subcat' in parent && 'length' in parent.subcat) {
for (var j = 0; j < parent.subcat.length; j++) {
if (parent.subcat[j].id === subID) {
return parent.id;
}
}
}
}
return null;
}
If you don't like your function returning null, you can always alter it so that it returns -1, assuming that -1 is out-of-band for your IDs. Note also that this is hardly an optimal solution, so if you're intending to use this for large amounts of data, you'll want to look into faster and/or more efficient search algorithms.
try this .we have to iterate through all the data
[fiddle][1]
Fiddle
var input = "sub 15";
var id =-1;
for(var i=0;i<theData.categories.length;i++){
if(theData.categories[i].subcat!=null){
for(var j=0;j<theData.categories[i].subcat.length;j++){
if(theData.categories[i].subcat[j].name==input){
id= theData.categories[i].id;
break;
}
}
}
}
console.log(id)
You might consider more a generic solution, which searches for a given key and a value in the subcat array. Then take only the first object's id.
function getParentId(key, value) {
return (theData.categories.filter(function (a) {
return a.subcat.some(function (b) {
return b[key] === value;
});
})[0] || {}).id;
}
var theData = { categories: [{ id: 661, name: "some name", description: "some description", subcat: [{ id: 662, name: "sub 1", translations: null }, { id: 663, name: "sub 2", translations: null }], image: null }, { id: 657, name: "some other name", description: 0, subcat: [{ id: 456, name: "sub 12", translations: null }, { id: 656, name: "sub 15", translations: null }], image: null }] };
console.log(getParentId('name', 'sub 15'));
This may not be the best way but hope this will be useful
var getSubCat = []; // create an empty array to map parent id with sub name
var getCat = theData.categories; // get categories
getCat.forEach(function(item) { // loop through categories
item.subcat.forEach(function(elem) {
getSubCat.push({
id: item.id, // this is parent id
sub: elem.name // name inside each subcat object. Total 4 subcat object
});
})
})
var parentId = getSubCat.filter(function(elem){ // filter the getSubCat array
return elem.sub ==='sub 15'
})[0].id // parentId is an array, we need first object so [0]
alert(parentId)
Now I am pushing name inside each of subcat object. On requirement you can also push their id
DEMO
The below solution looks similar to furkle's solution. But here it uses jquery to iterate through the json objects.
function getParent(subID) {
var parentId = null;
$.each(theData.categories, function(i, v)
{
$.each(v.subcat, function(idx, obj){
if(obj.name ==subID)
parentId = v.id
})
})
return parentId;
}
I have an array that contains different clothes and the type of the cloth. For example, I may have a specific shirt that belongs to the shirts category. What I want to do is get all the types from an array and ignore any duplicate entries. So if I have 3 shirts and 2 trousers, I will only get 1 shirt and 1 trouser.
array = [
{
name: "test 1",
type: "shirt"
},
{
name: "test 2",
type: "shirt"
},
{
name: "test 3",
type: "trousers"
},
{
name: "test 4",
type: "trousers"
}
];
var categories = {};
for(var i = 0, len = array.length; i < len; i++) {
if(categories.indexOf(array[i].type) > -1) {
console.log('Duplicate type');
}
else {
console.log('New type');
categories.push(array[i].type);
}
}
But I end up getting TypeError: categories.indexOf is not a function.
Pretty short solution using ES6 Set object:
The Set object lets you store unique values of any type, whether
primitive values or object references.
var categories = new Set();
array.forEach((o) => categories.add(o.type));
categories = [...categories]; // Set to Array transformation
console.log(categories); // ["shirt", "trousers"]
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Set
You need an array for categories, not an object.
var categories = [];
array = [
{
name: "test 1",
type: "shirt"
},
{
name: "test 2",
type: "shirt"
},
{
name: "test 3",
type: "trousers"
},
{
name: "test 4",
type: "trousers"
}
];
var categories = [];
for(var i = 0, len = array.length; i < len; i++) {
if(categories.indexOf(array[i].type) > -1) {
console.log('Duplicate type');
}
else {
console.log('New type');
categories.push(array[i].type);
}
}
console.log(categories);
This happens because you define categories as object literal ({}), rather than an array ([]):
// --------------vv
var categories = {};
Your issue is that you are trying to invoke .push method on an object but the method is available only on Array. You need to make categories an array in order to push to it.
As an alternative, you can use pure function without any mutations using Array.prototype.reduce() to reduce the array of duplicate objects to unique ones:
var array = [
{
name: "test 1",
type: "shirt"
},
{
name: "test 2",
type: "shirt"
},
{
name: "test 3",
type: "trousers"
},
{
name: "test 4",
type: "trousers"
}
];
function unique(input) {
return input.reduce(function (acc, current) {
if (acc.indexOf(current.type) > -1) {
return acc
} else {
return acc.concat([current.type]);
}
}, [])
}
var categories = unique(array);
console.log(categories);
If you want to see the result of every row then I think first implementation could be the answer but if you want just the categories then using map make it simple.
array = [
{ name: "test 1", type: "shirt" },
{ name: "test 2", type: "shirt" },
{ name: "test 3", type: "trousers" },
{ name: "test 4", type: "trousers" }
];
// --------------------------------------
var categories = [];
array.forEach(v => {
if (this[v.type])
return console.log('Duplicate type');
console.log('New type');
this[v.type] = true;
categories.push(v.type);
}, {});
console.log(categories);
// --------------------------------------
var map = new Map;
array.forEach(v => map.set(v.type, v.type));
categories = [...map.keys()];
console.log(categories);