I have an array of objects like following, some commands share the same text:
const Commands=[
{
id: "id1",
text: "read",
message: "read",
},
{
id: "id2",
text: "read",
message: "read a book",
},
{
id: "id3",
text: "sleep",
message: "sleep",
},
{
id: "id4",
text: "help",
message: "help",
},
{
id: "id5",
text: "help",
message: "command help",
},
]
I want to filter this array out based on the user input message. Also, for the commands that have the same text, I only want the first one (or the default one). For example, if the user input ["read a book"], the result would be
[
{
id: "id2",
text: "read",
message: "read a book",
},
{
id: "id3",
text: "sleep",
message: "sleep",
},
{
id: "id4",
text: "help",
message: "help",
},
]
if the user input ["read a message"], which does not exist in the array, the default one will be returned, the result would be
[
{
id: "id1",
text: "read",
message: "read",
},
{
id: "id3",
text: "sleep",
message: "sleep",
},
{
id: "id4",
text: "help",
message: "help",
},
]
Here is my JavaScripts/TypeScripts,
const defaultReadText =
Commands.find(
(command) => command.message === userReadMessage
)?.text ?? "read"
const defaultReadMessage =
Commands.find(
(command) => command.message === userReadMessage
)?.message ?? "read"
const defaultHelpText =
Commands.find(
(command) => command.message === userHelpMessage
)?.text ?? "help"
const defaultHelpMessage =
Commands.find(
(command) => command.message === userHelpMessage
)?.message ?? "help"
const enabledCommands =
Commands.filter(
(command) =>
(command.text === defaultReadText &&
command.message === defaultReadMessage) ||
command.text != defaultReadText
)?.filter(
(command) =>
(command.text === defaultHelpText &&
command.message === defaultHelpMessage) ||
command.text != defaultHelpText
)
I wonder if there is better way to solve this?
You could group by text and take the object for a matching message.
const
filter = (array, message) => Object.values(array.reduce((r, o) => {
if (!r[o.text] || o.message === message) r[o.text] = o;
return r;
}, {})),
commands = [{ id: "id1", text: "read", message: "read" }, { id: "id2", text: "read", message: "read a book" }, { id: "id3", text: "sleep", message: "sleep" }, { id: "id4", text: "help", message: "help" }, { id: "id5", text: "help", message: "command help" }];
console.log(filter(commands));
console.log(filter(commands, "read a book"));
console.log(filter(commands, "read a message"));
.as-console-wrapper { max-height: 100% !important; top: 0; }
A chainable approach with reduce
const
filter = message => (r, o) => {
if (r[r.length - 1]?.text === o.text) {
if (o.message === message) r[r.length - 1] = o;
} else {
r.push(o);
}
return r;
},
commands = [{ id: "id1", text: "read", message: "read" }, { id: "id2", text: "read", message: "read a book" }, { id: "id3", text: "sleep", message: "sleep" }, { id: "id4", text: "help", message: "help" }, { id: "id5", text: "help", message: "command help" }];
console.log(commands.reduce(filter(), []));
console.log(commands.reduce(filter("read a book"), []));
console.log(commands.reduce(filter("read a message"), []));
.as-console-wrapper { max-height: 100% !important; top: 0; }