Although it is a common problem but I couldn't find any lead to get the desired result. So here is the problem. I have the following array:
[
[ 'a' ]
[ 'a', 'b' ]
[ 'a', 'c' ]
[ 'a', 'c', 'd' ]
[ 'a', 'c', 'd', 'e' ]
]
And what I want as an end result is an object like this:
{
a: {
b: {},
c: { d: { e: {} } }
}
}
I don't understand which approach would be better to get this result and how to achieve it.
You need a double reduce, one for the outer array and one for the keys and the nesting objects.
var data = [['a'], ['a', 'b'], ['a', 'c'], ['a', 'c', 'd'], ['a', 'c', 'd', 'e']],
result = data.reduce((r, keys) => {
keys.reduce((o, k) => o[k] = o[k] || {}, r);
return r;
}, {});
console.log(result);
This question already has answers here:
Sort JavaScript object by key
(37 answers)
Closed 2 years ago.
Rookie Javascript question here: I have an object containing arrays like so
const obj = {
'red': [ 'a', 'b', 'c'],
'blue': [ 'a' ],
'green': [ 'a', 'b', 'c', 'd', 'e' ]
}
I want to sort my object so that the properties with the largest arrays come first
obj = {
'green': [ 'a', 'b', 'c', 'd', 'e' ],
'red': [ 'a', 'b', 'c'],
'blue': [ 'a' ]
}
Is there a simple one-liner or lodash method I can achieve this with?
Convert your object into an array. Sort the array according to your needs then re-build an object from that array as below :
const obj = {
'red': ['a', 'b', 'c'],
'blue': ['a'],
'green': ['a', 'b', 'c', 'd', 'e']
};
const ordered = {};
const asArray = Object.keys(obj).map(key => ({
key,
arr: obj[key]
})); // create an array from the object
asArray.sort((a, b) => b.arr.length - a.arr.length); // sor the array so the array has bigger length should come first
asArray.forEach(r => {
ordered[r.key] = r.arr
}); // re construct as new object
console.log(ordered);
First sort then assign
const obj = {
'red': [ 'a', 'b', 'c'],
'blue': [ 'a' ],
'green': [ 'a', 'b', 'c', 'd', 'e' ]
};
const newObj = {};
let sorted = Object.keys(obj)
.sort((a, b) => obj[b].length - obj[a].length).forEach(e => newObj[e] = obj[e]);
console.log(newObj);
So i'm making a react app and I have a list of projects that use specific technologies. I want the user to be able to be able to say i'm looking for a project that uses 'a', 'b', and 'c' technologies via some checkboxes (maybe) and the list of projects will automatically update. Should i just be using vanilla javascript for this (to sort through an array of objects) or is there an easier way to do it?
If this should be done via vanilla javascript, can someone give me a little direction please. was able to do this successfully search for just one 'technology' but couldn't quite get it done searching for multiple technologies.
Example data to be below.
const projects = [{
name: 'projecta',
technologies: ['a', 'b', 'f'],
link: 'www.example.com'
},
{
name: 'projectb',
technologies: ['c', 'd', 'e'],
link: 'www.example.com'
},
{
name: 'projectc',
technologies: ['a', 'b', 'c', 'd', 'e'],
link: 'www.example.com'
}];
You could use a destructuring while filtering with checking all wanted technologies.
const
projects = [{ name: 'projecta', technologies: ['a', 'b', 'f'], link: 'www.example.com' }, { name: 'projectb', technologies: ['c', 'd', 'e'], link: 'www.example.com' }, { name: 'projectc', technologies: ['a', 'b', 'c', 'd', 'e'], link: 'www.example.com' }],
search = ['c', 'e'],
result = projects.filter(({ technologies }) =>
search.every(s => technologies.includes(s)));
console.log(result);
.as-console-wrapper { max-height: 100% !important; top: 0; }
If you have multiple checkboxes you will get an array which contains the value of all selected checkboxes.
Filter the array based one or multiple values will work like this:
const projects = [
{
name: 'projecta',
technologies: ['a', 'b', 'f'],
link: 'www.example.com'
},
{
name: 'projectb',
technologies: ['c', 'd', 'e'],
link: 'www.example.com'
},
{
name: 'projectc',
technologies: ['a', 'b', 'c', 'd', 'e'],
link: 'www.example.com'
}
];
const search = ['c', 'e'];
const result = projects.filter(project => {
return search.every(s => project.technologies.includes(s));
});
// or
const result2 = projects.filter(project => {
return !search.some(s => project.technologies.indexOf(s) === -1);
});
console.log(result);
console.log(result2);
Yes you can do it using only vanilla JS, you can profit from Array's buil-in methods to do it.
You can use a combination of .filter() and .some() methods to filter your array based on the specified technologies list.
This is how should be your code:
const techs = ['a', 'c'];
var filtered = projects.filter(function(p){
return !techs.some(function(t){
return p.technologies.indexOf(t) === -1;
});
});
Demo:
const projects = [
{
name: 'projecta',
technologies: ['a', 'b', 'f'],
link: 'www.example.com'
},
{
name: 'projectb',
technologies: ['c', 'd', 'e'],
link: 'www.example.com'
},
{
name: 'projectc',
technologies: ['a', 'b', 'c', 'd', 'e'],
link: 'www.example.com'
}
];
const techs = ['a', 'c'];
var filtered = projects.filter(function(p){
return !techs.some(function(t){
return p.technologies.indexOf(t) === -1;
});
});
console.log(filtered);
Explanation:
We use filter() method to loop over the array filter its elements and in its callback function we use .some() method to test over the iterated project technologies to make sure they're all among of the given technologies list.
Assuming you store the selected technologies in an array, you could simply loop through each project with filter() and return those that have at least one of the techs.
In the snippet below we iterate through each project with filter, meaning we create an array with items that satisfy the criteria in the callback.
The callback does another filter for each tech of the current project, and returns the length of the filtered array. If no tech of the current project matches your selection, the array length is zero which is a falsy value and the whole object won't be returned to the new array.
For example:
let selectedTechs = ['a', 'b']; //selected techs
const projects = [
{
name: 'projecta',
technologies: ['a', 'b', 'f'],
link: 'www.example.com'
},
{
name: 'projectb',
technologies: ['c', 'd', 'e'],
link: 'www.example.com'
},
{
name: 'projectc',
technologies: ['a', 'b', 'c', 'd', 'e'],
link: 'www.example.com'
}
];
let arr = projects.filter(
(item) => item.technologies.filter((x) => selectedTechs.includes(x)).length
);
console.log(arr); //returns the 1st and 3rd project object.
and a demo in React:
class MyApp extends React.Component {
constructor() {
super();
this.state = {
technologies: ['a', 'b', 'c', 'd', 'e', 'f'],
checkedTechs: [],
projects: [
{
name: 'projecta',
technologies: ['a', 'b', 'f'],
link: 'www.example.com'
},
{
name: 'projectb',
technologies: ['c', 'd', 'e'],
link: 'www.example.com'
},
{
name: 'projectc',
technologies: ['a', 'b', 'c', 'd', 'e'],
link: 'www.example.com'
}
]
};
}
checkTech = (name) => {
let arr = this.state.checkedTechs.slice();
if(arr.includes(name)) {
arr.splice(arr.indexOf(name), 1);
} else {
arr.push(name);
}
this.setState({checkedTechs: arr});
}
render() {
let {technologies, checkedTechs, projects} = this.state;
return(
<div>
<div>
{technologies.map(
(item) => <label key={item}>{item}<input value={checkedTechs.indexOf(item)>-1} onChange={this.checkTech.bind(this, item)} type="checkbox" /></label>
)}
</div>
<ul>
{this.state.projects.filter(
(item) => item.technologies.filter((x) => checkedTechs.includes(x)).length
).map(
(item) => <li key={item.name}>{item.name}</li>
)}
</ul>
</div>
);
}
}
ReactDOM.render(<MyApp />, document.getElementById("app"));
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react-dom.js"></script>
<div id="app"></div>
The above is to show project that include the selected techs. If you want to select projects that have exactly the selected techs, replace the filter logic with:
(item) => item.technologies.join(',') === checkedTechs.sort().join(',')
You can use javascript for this. Say, in each click of checkbox your checkbox value is saved in choice then you can get the objects like this,
const projects = [
{
name: 'projecta',
technologies: ['a', 'b', 'f'],
link: 'www.example.com'
},
{
name: 'projectb',
technologies: ['c', 'd', 'e'],
link: 'www.example.com'
},
{
name: 'projectc',
technologies: ['a', 'b', 'c', 'd', 'e'],
link: 'www.example.com'
}
];
var choice = 'e';
var res= projects.filter((x)=>{
if(x.technologies.indexOf(choice) !== -1){
return x;
}
});
console.log(res);
I've found something that works. best solution?
const checkFor = ['a', 'b'];
const winners = projects.filter(project => {
return checkFor.every(function(val) {
return project.technologies.indexOf(val) !== -1;
});
});
console.log('winners: ', winners);
Is there any utility function which works like lodash.pull but for Ruby arrays?
You can use the delete method to remove occurrences of a single value:
arr = ['a', 'b', 'c', 'b', 'c', 'd']
arr.delete 'b'
# ['a', 'c', 'c', 'd']
Or you can use the - or -= operator to delete an array of values.
arr = ['a', 'b', 'c', 'b', 'c', 'd']
arr -= ['a', 'c']
# ['b', 'b', 'd']
There are several equivalent of the _.pull, but they work with one value at a time.
You could use
[:a, :b, :c, :a, :b].delete(:a) # => can't accept multiple arguments
Or you could use
[:a, :b, :c, :a, :b].delete_if{|x| [:a, :b].include? x}
Or you could use #andrunix approach above by subtracting the array:
arr = ['a', 'b', 'c', 'b', 'c', 'd']
arr -= ['a', 'c']
Hi I was wondering if I can get some help here I am stuck. I am trying to create a histogram function that takes an array like ['a', 'a', 'b', 'c', 'b', 'a'] and returns {a:3, b:2, c:1} using the reduce function to build the histogram function. But I am stuck on what the callback function should be.
Thank you for any responses.
You can reduce your array like this:
['a', 'a', 'b', 'c', 'b', 'a'].reduce(function(obj, value) {
obj[value] = obj[value] || 0;
obj[value]++;
return obj;
}, {});
If your environment supports Object.assign() and ES6 you can also do this:
['a', 'a', 'b', 'c', 'b', 'a']
.reduce((a, b) => Object.assign(a, {[b]: a[b] ? ++a[b] : 1}), {});
Try to iterate over the array and fill/increment the object's value accordingly,
var x = ['a', 'a', 'b', 'c', 'b', 'a'];
var y = {};
x.forEach(function(itm){
y[itm] = ++y[itm] || 1;
});