How to search in JSON with Javascript fast? - javascript

I have a lemmatization nested dictionaries, like
{
{"abbreviate": ["abbreviated","abbreviates","abbreviating"]},
{"abdicate": ["abdicated","abdicates","abdicating"]}
}
I want to fast search inside values to get the according key (find abbreviated → output abbreviate). Fast - because the file is about 6MB. This search will be used in a Chrome extension, so i would strongly prefer Javascript, not Python.
What are technics to accomplish such search?

It seems to me that you need to convert an object to a form for quick hash search:
{
abbreviated: 'abbreviate',
abbreviates: 'abbreviate',
abbreviating: 'abbreviate',
abdicated: 'abdicate',
abdicates: 'abdicate',
abdicating: 'abdicate',
};
const data = {
abbreviate: ['abbreviated', 'abbreviates', 'abbreviating'],
abdicate: ['abdicated', 'abdicates', 'abdicating'],
};
const dictionary = Object.keys(data).reduce((dict, key) => {
const records = data[key];
const obj = records.reduce((acc, val) => ({ ...acc, [val]: key }), {});
return { ...dict, ...obj };
}, {});
console.log(dictionary['abbreviated']);

Related

How to change an array to a JSON format with javascript

I have an array which is in the below format
node=['ADSss|623', 'sss|635']
I want this to be in a json format as below
[
{
"623": "ADSss"
},
{"635": "sss"
}
]
Is there a simple way to achieve this? it is possible with map function, but i felt it is adding up too many lines of code
Assuming that you array only contain string of format ${value}|${key}, you can map those to an object:
const result = node.map((arrayEl) => {
// Split you array string into value and keys
const [value, key] = arrayEl.split('|');
// return an object key: value
return {[key]: value}
});
console.log(result);
In one line :
const node=['ADSss|623', 'sss|635'];
const json = node.reduce((p, n) => ({ ...p, [n.split('|')[1]]: n.split('|')[0] }), {});
const jsonArray = node.map(n => ({ [n.split('|')[1]]: n.split('|')[0] }));
console.log(json);
console.log(jsonArray);

Typescript filter to select object with value of specific words

I have an array of objects in my DB records.
The record:
{"ID123":{"FileID":"12345","FileName":"ABCFile_ver5_44453.PDF"},"DocID":6009,"DocFormat":"PDF"}
The format to store the filename in my DB is always with "FileName": "actual_fileName.PDF".
I want to only get the object with "FileName":"....", to only display the filename instead of other objects.
This is my code:
getValue(): Atts[] | any {
if (this.isEmptyValue()) {
return [];
}
return !this.useObject ? this.value : Object.entries(this.value).map(([key, value]) => ({ key, value })).filter(value=);
}
How do I filter the object that contains "FileName" so that I can display the filename in my application?
I'm stuck at the filter method.
I had to reduce your code a little to a minimal reproducible example, and I made the assumption that this.value in your Object.entries is the entire DB record that you have listed above. I converted this to an object so I could process it in my code. So, your mileage may vary if my assumption was incorrect.
let obj = {
"ID123": {
"FileID": "12345",
"FileName": "ABCFile_ver5_44453.PDF"
},
"DocID": 6009,
"DocFormat": "PDF"
};
let result = { "FileName": Object.entries(obj).map(([key, value]) => ({
key,
value
})).filter(keyValuePair => {
if (keyValuePair.value.FileName) {
return true;
}
})[0].value.FileName };
This returns:
{
"FileName": "ABCFile_ver5_44453.PDF"
}
Your filter step is filtering an array of key value pairs, so when filtering, you need to return true only if the 'value' is an object that has a property of FileName.
EDIT:
I realized that the way I wrote this will not work if the returned object from the array does not have value (or is undefined), so it's probably a better idea to store this in a variable first, and then return an object based on that varible, like so:
let fileNameObj = Object.entries(obj).map(([key, value]) => ({
key,
value
})).filter(keyValuePair => {
if (keyValuePair && keyValuePair.value.FileName) {
return true;
}
})[0];
if (fileNameObj && fileNameObj.FileName) {
let result = { "FileName": fileNameObj.FileName };
}

Filter array of objects by their values

I wish to iterate over an array of objects, which for purposes of illustration here are Users. I would like to filter those Users using a search term provided and the value of each of the objects properties.
I have come up with the following working solution, however, I am looking to see if anyone has a more elegant method?
let users = [
{
first_name: "Super",
last_name: "User"
},
{
first_name: "Admin",
last_name: "Istrator"
}
];
function filterObjects(collection, term) {
let filtered = [];
_.each(collection, obj => {
_.forOwn(obj, (value, key) => {
if (value.includes(term)) {
filtered.push(obj);
}
});
});
return filtered;
}
console.log(filterUsers(users, "Su"));
[Edit]
I make no assumptions about the structure, or the name, or quantity of any fields on the objects, therefore I do not want to use things like object.field_name === 'something' for example.
You can filter, and use _.some() to iterate the values, and check with Array.includes() (or lodash equivalent) if the term exists in the value.
const filterUsers = (collection, term) =>
collection.filter(o => _.some(o, v => v.includes(term)));
const users = [{"first_name":"Super","last_name":"User"},{"first_name":"Admin","last_name":"Istrator"}];
console.log(filterUsers(users, "Su"));
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.15/lodash.js"></script>
And the same idea using lodash/fp:
const { filter, some, includes } = _;
const filterUsers = term => filter(some(includes(term)));
const users = [{"first_name":"Super","last_name":"User"},{"first_name":"Admin","last_name":"Istrator"}];
console.log(filterUsers("Su")(users));
<script src='https://cdn.jsdelivr.net/g/lodash#4(lodash.min.js+lodash.fp.min.js)'></script>

Accumulating a Map from an Array In TypeScript

I have an array of TypeScript objects with shape that is essentially the following:
interface MyObject {
id: string
position: number
}
I am trying to convert this array into a map of id to position that looks like this for a JSON POST down the line:
{
"id1": 1,
"id2": 2,
}
One approach is to use an ES6 Map:
array.reduce((map, obj) => map.set(obj.id, obj.position), new Map())
That works, but converting an ES6 Map to JSON is problematic.
I have tried to accumulate the key-value pairs into a pure object literal, but TypeScript has been hating everything I try, which includes Indexable Types, Object.create({}), and a lot of other ideas.
How can I distill a pure object literal of key value pairs from an array of objects?
If your target environment supports ES2019, you could use Object.fromEntries(), like this:
function arrToObjES2019(arr: MyObject[]) {
return Object.fromEntries(arr.map(({ id, position }) => [id, position]));
}
Or, if not, you can make your own polyfill-like version of Object.fromEntries() using array reduce() on an empty object, like this:
function fromEntries<V>(iterable: Iterable<[string, V]>) {
return [...iterable].reduce((obj, [key, val]) => {
obj[key] = val
return obj
}, {} as {[k: string]: V})
}
and then use it:
function arrToObj(arr: MyObject[]) {
return fromEntries(arr.map(({ id, position }) => [id, position]));
}
Either way should let you do what you want:
const arr: MyObject[] = [
{ id: "id1", position: 1 },
{ id: "id2", position: 2 }
];
console.log(JSON.stringify(arrToObj(arr))); // {"id1":1,"id2":2}
Okay, hope that helps. Good luck!
Link to code
I'm not sure why reduce wouldn't be the approach here...
array.reduce((acc, val) =>
Object.assign(acc, {[val.id]: val.position}), {});
Just do this, it is the simplest way:
let newMap = new Map(array.map(obj => [obj.id, obj.position]));

How can i use ramda.js with this code?

I am beginning to use ramda, but have doubts about how to implement functions ramda.
This code is to mount a select object to do queries for sequelize.
See code:
const stringRequired = string => !!string.length
const numberRequired = number => Number.isInteger(number)
const validadeInput = (value, initial, validade) => (
validade(value) ? value : initial
)
const input = (obj, key, initial, validade) => (
typeof obj[key] !== 'undefined' ?
validadeInput(obj[key], initial, validade) :
initial
);
const addValue = (obj, key, value) => {
const prop = {}
prop[key] = value
return Object.assign(obj, prop)
}
const addFilter = (obj, key, value, validate) => (
validate(value) ? addValue(obj, key, value)
: obj
)
const selector = (query = {}) => {
const limit = input(query, 'limit', 10, numberRequired);
const name = input(query, 'name', '', stringRequired);
let select = {}
select = addFilter(select, 'name', name, stringRequired);
select = addFilter(select, 'limit', limit, numberRequired);
return select
}
console.log(selector());
// { limit: 10 }
console.log(selector({ name: 'David Costa' }));
// { limit: 10, name: 'David Costa' }
console.log(selector({ limit: 50 }));
// { limit: 50 }
Or see demo on link
http://jsbin.com/zerahay/edit?js,console,output
Why?
I think you need to consider why you want to convert this to Ramda
(Disclaimer: I'm a Ramda author) Ramda is a library, a toolkit. Use it when it helps clean up your code or when it makes it easier to understand the problem and its solution. Don't use it when it doesn't.
That said, I did refactor it, using Ramda:
A Refactoring
I simply tried to refactor it a bit. In the end, I replaced all your helper functions with a single one that takes a list of conditions such as ['limit', 10, numberRequired] to create a function equivalent to your selector.
I did use a few Ramda functions along the way, but the only one that offers substantive help is assoc, which creates a new object from an old one and a key and value. Using, for instance, compose(Boolean, length) is cleaner than const stringRequired = string => !!string.length, but it's not a large difference.
The important change, to my mind, is the makeSelector function, which makes creating your selector function much more declarative. It's a bit ugly, and I probably would write it differently if I were starting from scratch, but I did this in a series of steps, inlining your helper functions until I had a reasonably short function that had the same behavior.
// rules
const stringRequired = R.compose(Boolean, R.length)
const numberRequired = number => Number.isInteger(number)
// utils
const makeSelector = (conditions) => (query = {}) => R.reduce(
(select, [key, initial, validate]) => {
const value = key in select && validate(select[key]) ? select[key] : initial;
return validate(value) ? R.assoc(key, value, select) : select
},
query,
conditions
)
// main
const selector = makeSelector([
['limit', 10, numberRequired],
['name', '', stringRequired]
])
console.log(selector());
console.log(selector({ name: 'David Costa' }));
console.log(selector({ limit: 50 }));
<script src="//cdnjs.cloudflare.com/ajax/libs/ramda/0.25.0/ramda.js"></script>
I'm a little hesitant to simply respond with a translated block of code and my recommendation for learning going forward would be to try replace the functions you already have one by one with those from Ramda.
Hesitation aside, the following offers one example of what your code might look like when using various functions from Ramda.
// The existing check for `!!string.length` allows for potential issues with
// arrays being passed in and incorrectly validating, so this will ensure the
// value is indeed a string before checking its length
const stringRequired = R.both(R.is(String), R.complement(R.isEmpty))
// `addFilter` produces a function that takes an object and uses the provided
// function to validate the value associated with the provided key if it exists
// otherwise using the provided `initial` value. If valid, an object containing
// the key and value will be returned, otherwise an empty object is returned.
const addFilter = (validate, initial, key) =>
R.pipe(
R.propOr(initial, key),
R.ifElse(validate, R.objOf(key), R.always({}))
)
// `selector` takes an object and passes it to each function generated by
// calling `addFilter`, merging the resulting objects together.
const selector = (q = {}) =>
R.converge(R.merge, [
addFilter(stringRequired, '', 'name'),
addFilter(Number.isInteger, 10, 'limit')
])(q)
console.log(selector())
console.log(selector({ name: 'David Costa' }))
console.log(selector({ limit: 50 }))
<script src="//cdnjs.cloudflare.com/ajax/libs/ramda/0.25.0/ramda.min.js"></script>

Categories

Resources