如何用lodash重构这个double for Loop?
How to refactor this double forLoop with lodash?
我有 selectedTags
,最多可容纳 3 个标签。
vm.tags
可能包含数千个,很可能只有数百个我也需要比较的标签。
如果 3 个标签的 ID 与 vm.tags
中的一个标签的 ID 匹配,我需要打开它们的边框。还有 3 个边框:border1
、border2
、border3
.
const tagsColorCheck = () => {
let name, selected, its_ticker;
let selectedTags = TagsFactory.retrieveTickerTags('onlyTags');
if (selectedTags.length > 0) {
for (let i=0; i<vm.tags.length; i++) {
for (let j=0; j<selectedTags.length; j++) {
if (selectedTags[j].term_id == vm.tags[i].term_id) {
name = 'border'+ ( j + 1 );
selected = 'selected';
its_ticker = 'its_ticker';
vm.tags[i][name] = true;
vm.tags[i][selected] = true;
vm.tags[i][its_ticker] = selectedTags[j].its_ticker;
}
}
}
}
};
到目前为止,这是我正在处理的内容 (_.each
):
const tagsColorCheck = () => {
let name, selected, its_ticker, vmTerm, term_1, term_2, term_3, ticker_1, ticker_2, ticker_3;
let selectedTags = TagsFactory.retrieveTickerTags('onlyTags');
if (!_.isEmpty(selectedTags)) {
vmTerm = R.findIndex(R.propEq('term_id', selectedTags[0].term_id))(vm.tags);
}
if (selectedTags[0]) { term_1 = parseInt(selectedTags[0].term_id); ticker_1 = selectedTags[0].its_ticker; }
if (selectedTags[1]) { term_2 = parseInt(selectedTags[1].term_id); ticker_2 = selectedTags[1].its_ticker; }
if (selectedTags[2]) { term_3 = parseInt(selectedTags[2].term_id); ticker_3 = selectedTags[2].its_ticker; }
_.each(vm.tags, (tag) => {
if (tag.term_id === term_1) {
tag.selected = true;
tag.border1 = true;
tag.its_ticker = ticker_1;
}
if (tag.term_id === term_2) {
tag.selected = true;
tag.border2 = true;
tag.its_ticker = ticker_2;
}
if (tag.term_id === term_3) {
tag.selected = true;
tag.border3 = true;
tag.its_ticker = ticker_3;
}
})
};
还有这个 (for of loop
):
const tagsColorCheck = () => {
let name, selected, its_ticker, vmTerm, term_1, term_2, term_3, ticker_1, ticker_2, ticker_3;
let selectedTags = TagsFactory.retrieveTickerTags('onlyTags');
const borderRizeTag = (tag) => {
if (tag.term_id === term_1) {
tag.selected = true;
tag.border1 = true;
tag.its_ticker = ticker_1;
}
if (tag.term_id === term_2) {
tag.selected = true;
tag.border2 = true;
tag.its_ticker = ticker_2;
}
if (tag.term_id === term_3) {
tag.selected = true;
tag.border3 = true;
tag.its_ticker = ticker_3;
}
return tag;
}
if (!_.isEmpty(selectedTags)) {
vmTerm = R.findIndex(R.propEq('term_id', selectedTags[0].term_id))(vm.tags);
}
if (selectedTags[0]) { term_1 = parseInt(selectedTags[0].term_id); ticker_1 = selectedTags[0].its_ticker; }
if (selectedTags[1]) { term_2 = parseInt(selectedTags[1].term_id); ticker_2 = selectedTags[1].its_ticker; }
if (selectedTags[2]) { term_3 = parseInt(selectedTags[2].term_id); ticker_3 = selectedTags[2].its_ticker; }
for (let tag of vm.tags) {
console.log(tag);
tag = borderRizeTag(tag);
}
console.log('vmTerm',vmTerm);
};
想出了一个很棒的解决方案! :D 同时使用 _lodash and ramda.
所以在下面,立即 each
可以更快地推理,然后使用 R.equals
来比较 term_ids
是否匹配。然后在正确的 tag
对象上设置键的值。
if (!_.isEmpty(selectedTags)) {
_.each(vm.tags, tag => {
_.each(selectedTags, (selectedTag, index) => {
let areTermIDsSame = R.equals;
if (areTermIDsSame(parseInt(selectedTag.term_id), parseInt(tag.term_id))) {
name = 'border'+ ( index + 1 );
selected = 'selected';
its_ticker = 'its_ticker';
tag[name] = true;
tag[selected] = true;
tag[its_ticker] = selectedTag.its_ticker;
}
});
})
}
ES6 fiddle 到 运行: http://www.es6fiddle.net/is0prsq9/ (注意,复制整个文本,并将其粘贴到浏览器控制台或节点 REPL 中,然后检查 tags
查看结果)
它不是 lodash,在 ES6 结构中你真的不需要它。相关代码:
const tagsColorCheck = () => {
let tags = TagsFactory.retrieveTickerTags('onlyTags')
sel.forEach( (s,i) =>
tags.filter(t => t.term_id === s.term_id).forEach( t => {
t['border' + (i+1)] = true
t.selected = true
t.its_ticker = s.its_ticker
})
)
return tags
}
如果您使用函数式语言编写此代码,您可以访问 list comprehension and it would be a bit cleaner. Essentially, this is a pretty clear case of (for every x in a and y in b)
so a list comprehension is what you need, but you don't have it in javascript (mozilla has it,但在该领域之外没有用处)。
结果是一种有点实用的方法——但是,它永远不可能在纯粹的 javascript 中真正起作用。功能范式最重要的好处可能是 immutable data structures 您可以在其中编写新列表。相反,您只需在此处修改它们,这实际上根本不是很实用。尽管如此,如果您更喜欢 each
方法而不是文字增量方法,就像您在上面所做的以及我在 post 中所做的那样,那么它是一种(虽然速度较慢但可以说更干净)更好的方法。
想法很简单 - 通过 term_id
创建所有标签的索引。迭代选定的标签。如果通过标签索引中的 id 找到标签,则通过分配具有新属性的对象来改变它。
顺便说一句 - 唯一需要 lodash 的是 _.keyBy()
,如果你不想使用 lodash,你可以使用 Array.prototype.reduce
轻松做到这一点。
/** mocked vm **/
const vm = {
tags: [{ term_id: 1 }, { term_id: 2 }, { term_id: 3 }, { term_id: 4 }, { term_id: 5 }, { term_id: 6 }]
}
/** mocked TagsFactory **/
const TagsFactory = {
retrieveTickerTags: () => [{ term_id: 1, its_ticker: 'ticker 1' }, { term_id: 4, its_ticker: 'ticker 4' }, { term_id: 5, its_ticker: 'ticker 5' }]
};
const tagsColorCheck = () => {
const selectedTags = TagsFactory.retrieveTickerTags('onlyTags');
if (selectedTags.length === 0) { // if selectedTags is empty exit
return;
}
const vmTagsIndex = _.keyBy(vm.tags, (tag) => tag.term_id); // create an index of tags by term_id
selectedTags.forEach(({
term_id, its_ticker
}, index) => { // loop through selectd tags and retreive term_id and its_ticker from the current selected tag
const tag = vmTagsIndex[term_id]; // find the tag in the vmTagsIndex
if (!tag) { // if the id doesn't exist in vmTagsIndex exit
return;
}
Object.assign(tag, { // mutate the tag by assigining it an object with the available properties
selected: true,
[`border${index + 1}`]: true,
its_ticker
});
});
};
tagsColorCheck();
console.log(vm.tags);
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.15.0/lodash.min.js"></script>
我有 selectedTags
,最多可容纳 3 个标签。
vm.tags
可能包含数千个,很可能只有数百个我也需要比较的标签。
如果 3 个标签的 ID 与 vm.tags
中的一个标签的 ID 匹配,我需要打开它们的边框。还有 3 个边框:border1
、border2
、border3
.
const tagsColorCheck = () => {
let name, selected, its_ticker;
let selectedTags = TagsFactory.retrieveTickerTags('onlyTags');
if (selectedTags.length > 0) {
for (let i=0; i<vm.tags.length; i++) {
for (let j=0; j<selectedTags.length; j++) {
if (selectedTags[j].term_id == vm.tags[i].term_id) {
name = 'border'+ ( j + 1 );
selected = 'selected';
its_ticker = 'its_ticker';
vm.tags[i][name] = true;
vm.tags[i][selected] = true;
vm.tags[i][its_ticker] = selectedTags[j].its_ticker;
}
}
}
}
};
到目前为止,这是我正在处理的内容 (_.each
):
const tagsColorCheck = () => {
let name, selected, its_ticker, vmTerm, term_1, term_2, term_3, ticker_1, ticker_2, ticker_3;
let selectedTags = TagsFactory.retrieveTickerTags('onlyTags');
if (!_.isEmpty(selectedTags)) {
vmTerm = R.findIndex(R.propEq('term_id', selectedTags[0].term_id))(vm.tags);
}
if (selectedTags[0]) { term_1 = parseInt(selectedTags[0].term_id); ticker_1 = selectedTags[0].its_ticker; }
if (selectedTags[1]) { term_2 = parseInt(selectedTags[1].term_id); ticker_2 = selectedTags[1].its_ticker; }
if (selectedTags[2]) { term_3 = parseInt(selectedTags[2].term_id); ticker_3 = selectedTags[2].its_ticker; }
_.each(vm.tags, (tag) => {
if (tag.term_id === term_1) {
tag.selected = true;
tag.border1 = true;
tag.its_ticker = ticker_1;
}
if (tag.term_id === term_2) {
tag.selected = true;
tag.border2 = true;
tag.its_ticker = ticker_2;
}
if (tag.term_id === term_3) {
tag.selected = true;
tag.border3 = true;
tag.its_ticker = ticker_3;
}
})
};
还有这个 (for of loop
):
const tagsColorCheck = () => {
let name, selected, its_ticker, vmTerm, term_1, term_2, term_3, ticker_1, ticker_2, ticker_3;
let selectedTags = TagsFactory.retrieveTickerTags('onlyTags');
const borderRizeTag = (tag) => {
if (tag.term_id === term_1) {
tag.selected = true;
tag.border1 = true;
tag.its_ticker = ticker_1;
}
if (tag.term_id === term_2) {
tag.selected = true;
tag.border2 = true;
tag.its_ticker = ticker_2;
}
if (tag.term_id === term_3) {
tag.selected = true;
tag.border3 = true;
tag.its_ticker = ticker_3;
}
return tag;
}
if (!_.isEmpty(selectedTags)) {
vmTerm = R.findIndex(R.propEq('term_id', selectedTags[0].term_id))(vm.tags);
}
if (selectedTags[0]) { term_1 = parseInt(selectedTags[0].term_id); ticker_1 = selectedTags[0].its_ticker; }
if (selectedTags[1]) { term_2 = parseInt(selectedTags[1].term_id); ticker_2 = selectedTags[1].its_ticker; }
if (selectedTags[2]) { term_3 = parseInt(selectedTags[2].term_id); ticker_3 = selectedTags[2].its_ticker; }
for (let tag of vm.tags) {
console.log(tag);
tag = borderRizeTag(tag);
}
console.log('vmTerm',vmTerm);
};
想出了一个很棒的解决方案! :D 同时使用 _lodash and ramda.
所以在下面,立即 each
可以更快地推理,然后使用 R.equals
来比较 term_ids
是否匹配。然后在正确的 tag
对象上设置键的值。
if (!_.isEmpty(selectedTags)) {
_.each(vm.tags, tag => {
_.each(selectedTags, (selectedTag, index) => {
let areTermIDsSame = R.equals;
if (areTermIDsSame(parseInt(selectedTag.term_id), parseInt(tag.term_id))) {
name = 'border'+ ( index + 1 );
selected = 'selected';
its_ticker = 'its_ticker';
tag[name] = true;
tag[selected] = true;
tag[its_ticker] = selectedTag.its_ticker;
}
});
})
}
ES6 fiddle 到 运行: http://www.es6fiddle.net/is0prsq9/ (注意,复制整个文本,并将其粘贴到浏览器控制台或节点 REPL 中,然后检查 tags
查看结果)
它不是 lodash,在 ES6 结构中你真的不需要它。相关代码:
const tagsColorCheck = () => {
let tags = TagsFactory.retrieveTickerTags('onlyTags')
sel.forEach( (s,i) =>
tags.filter(t => t.term_id === s.term_id).forEach( t => {
t['border' + (i+1)] = true
t.selected = true
t.its_ticker = s.its_ticker
})
)
return tags
}
如果您使用函数式语言编写此代码,您可以访问 list comprehension and it would be a bit cleaner. Essentially, this is a pretty clear case of (for every x in a and y in b)
so a list comprehension is what you need, but you don't have it in javascript (mozilla has it,但在该领域之外没有用处)。
结果是一种有点实用的方法——但是,它永远不可能在纯粹的 javascript 中真正起作用。功能范式最重要的好处可能是 immutable data structures 您可以在其中编写新列表。相反,您只需在此处修改它们,这实际上根本不是很实用。尽管如此,如果您更喜欢 each
方法而不是文字增量方法,就像您在上面所做的以及我在 post 中所做的那样,那么它是一种(虽然速度较慢但可以说更干净)更好的方法。
想法很简单 - 通过 term_id
创建所有标签的索引。迭代选定的标签。如果通过标签索引中的 id 找到标签,则通过分配具有新属性的对象来改变它。
顺便说一句 - 唯一需要 lodash 的是 _.keyBy()
,如果你不想使用 lodash,你可以使用 Array.prototype.reduce
轻松做到这一点。
/** mocked vm **/
const vm = {
tags: [{ term_id: 1 }, { term_id: 2 }, { term_id: 3 }, { term_id: 4 }, { term_id: 5 }, { term_id: 6 }]
}
/** mocked TagsFactory **/
const TagsFactory = {
retrieveTickerTags: () => [{ term_id: 1, its_ticker: 'ticker 1' }, { term_id: 4, its_ticker: 'ticker 4' }, { term_id: 5, its_ticker: 'ticker 5' }]
};
const tagsColorCheck = () => {
const selectedTags = TagsFactory.retrieveTickerTags('onlyTags');
if (selectedTags.length === 0) { // if selectedTags is empty exit
return;
}
const vmTagsIndex = _.keyBy(vm.tags, (tag) => tag.term_id); // create an index of tags by term_id
selectedTags.forEach(({
term_id, its_ticker
}, index) => { // loop through selectd tags and retreive term_id and its_ticker from the current selected tag
const tag = vmTagsIndex[term_id]; // find the tag in the vmTagsIndex
if (!tag) { // if the id doesn't exist in vmTagsIndex exit
return;
}
Object.assign(tag, { // mutate the tag by assigining it an object with the available properties
selected: true,
[`border${index + 1}`]: true,
its_ticker
});
});
};
tagsColorCheck();
console.log(vm.tags);
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.15.0/lodash.min.js"></script>