对于我想要使用多个谓词过滤它的数据列表,然后对每个过滤器执行操作。
EG。如果我的数据是:
var people = [
{name: 'Sachin', profession: 'doctor', cases: 12},
{name: 'Djokovic', profession: 'lawyer', cases: 14},
{name: 'Paes', profession: 'doctor', cases: 36},
{name: 'Jordan', profession: 'lawyer', cases: 78},
{name: 'Williams', profession: 'doctor', cases: 30},
{name: 'Nehwal', profession: 'lawyer', cases: 75}
]
我想将其转换为:
var peopleWithoutCases = [
{name: 'Sachin', profession: 'doctor', patients: 12, cases: 12},
{name: 'Djokovic', profession: 'lawyer', courtcases: 14, cases: 14},
{name: 'Paes', profession: 'doctor', patients: 36, cases: 36},
{name: 'Jordan', profession: 'lawyer', courtcases: 78, cases: 78},
{name: 'Williams', profession: 'doctor', patients: 30, cases: 30},
{name: 'Nehwal', profession: 'lawyer', courtcases: 75, cases: 75}
]
是否有像这样的优雅功能方法?
people
.filter (person => person.profession == 'doctor')
.map (person => {
person.patients = person.cases
return person;
})
.filter (person => person.profession == 'lawyer')
.map (person => {
person.courtcases = person.cases
return person;
})
问题是第一个map
返回一个只有doctor
s的数组。因此,第二个filter
会返回[]
。
我知道我可以这样做:
_.union(
people
.filter (person => person.profession == 'doctor')
.map (person => {
person.patients = person.cases
return person;
}),
people
.filter (person => person.profession == 'lawyer')
.map (person => {
person.courtcases = person.cases
return person;
})
)
如果我错了,请纠正我但是,这需要一个多次方法解决我的效率低下的问题随着数组列表的增长和谓词数量的增长,意见越来越强烈。
使用命令式方法很容易写出来。包含多个for
语句的单个if
循环。高效但不优雅:)
请使用功能javascript(如Underscore,LoDash或Excellent RamdaJS库)建议最佳方法。它是如何用纯函数式语言完成的?
注意:
答案 0 :(得分:1)
尝试这样:
var el = document.getElementById('dbg');
var $l = function( val ){
el.innerHTML = el.innerHTML + '<div class="line"><pre>' + val + '</pre></div>';
}
var people = [
{name: 'Sachin', profession: 'doctor', cases: 12},
{name: 'Djokovic', profession: 'lawyer', cases: 14},
{name: 'Paes', profession: 'doctor', cases: 36},
{name: 'Jordan', profession: 'lawyer', cases: 78},
{name: 'Williams', profession: 'doctor', cases: 30},
{name: 'Nehwal', profession: 'lawyer', cases: 75},
{name: 'Nawak', profession: 'developper', cases: 750}
]
var modifiers = {
'doctor' : function( ){ this.patients =this.cases ; return this} ,
'lawyer' : function( ){ this.courtcases = this.cases; return this; } ,
'developper' : function( ){ this.program = this.cases; return this; } ,
}
var result = people.map(function( p){
modifiers[p.profession].call( p );
return p;
})
console.dir(result);
$l( JSON.stringify( result , null , ' ' ) );
&#13;
.line {
border : solid 1px #AAA;
padding : 3px;
margin : 3px;
}
&#13;
<div id='dbg'></div>
&#13;
答案 1 :(得分:1)
使用Array.prototype.map
迭代对象,克隆对象(使用Object.assign()
,_.assign()
或_.extend()
)以防止更改原始对象,并使用{{应用过滤器3}}:
var people = [{"name":"Sachin","profession":"doctor","cases":12},{"name":"Djokovic","profession":"lawyer","cases":14},{"name":"Paes","profession":"doctor","cases":36},{"name":"Jordan","profession":"lawyer","cases":78},{"name":"Williams","profession":"doctor","cases":30},{"name":"Nehwal","profession":"lawyer","cases":75}];
var propsMap = {
'doctor': 'patients',
'lawyer': 'courtcases'
};
var filters = [
function cases2Prof(person) {
person[propsMap[person.profession]] = person.cases;
return person;
},
function removeCases(person) {
delete person.case;
return person;
}
];
var result = applyFilters(people, filters);
function applyFilters(array, filters) {
return array.map(function(item) {
var cloned = Object.assign({}, item); // clone the object to prevent mutating the original
// run all filters on the object
return filters.reduce(function(object, filter) {
return filter(cloned);
}, cloned);
});
}
console.table(result);
document.getElementById('demo').innerHTML = JSON.stringify(result, null, ' ');
<pre id="demo"></pre>
答案 2 :(得分:1)
并行完成2个过滤操作的要求,指的是在这里使用reduce,而不是filter。
使用lodash-fp专门使用流功能样式,否则可以使用普通的lodash / underscore。
var people = [
{name: 'Sachin', profession: 'doctor', cases: 12},
{name: 'Djokovic', profession: 'lawyer', cases: 14},
{name: 'Paes', profession: 'doctor', cases: 36},
{name: 'Jordan', profession: 'lawyer', cases: 78},
{name: 'Williams', profession: 'doctor', cases: 30},
{name: 'Nehwal', profession: 'lawyer', cases: 75},
{name: 'Nawak', profession: 'developper', cases: 750}
]
var mapper = {"doctor": "patients", "lawyer": "courtcases"};
var process = _.flow(_.reduce((r, e, i) => [...r, mapper[e.profession] && {
...e,
[mapper[e.profession]]: e.cases
}], []), _.compact);
console.log(process(people))
&#13;
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash-fp/0.10.4/lodash-fp.js"></script>
&#13;
答案 3 :(得分:0)
我认为这种解决方案很优雅,而且我认为它也是线性时间。 您可能不需要像我一样使用Ramda.js。
var people = [
{name: 'Sachin', profession: 'doctor', cases: 12},
{name: 'Djokovic', profession: 'lawyer', cases: 14},
{name: 'Paes', profession: 'doctor', cases: 36},
{name: 'Jordan', profession: 'lawyer', cases: 78},
{name: 'Williams', profession: 'doctor', cases: 30},
{name: 'Nehwal', profession: 'lawyer', cases: 75}
]
const professionToCaseType = {
doctor: 'patients',
lawyer: 'courtcases',
}
const transformPerson = (person) =>
R.assoc(professionToCaseType[person.profession], person.cases, person)
const transformPeople =
R.map(transformPerson)
console.log(transformPeople(people))
<script src="//cdnjs.cloudflare.com/ajax/libs/ramda/0.25.0/ramda.min.js"></script>