2016-07-27 2 views
0

Я должен перебрать массив, найти соответствующие объекты в другом массиве, объединить результат в объект.Как перебрать несколько массивов без вложенных наблюдаемых

Предположим, у меня есть три массива

var users = [ 
    { name: "A", type: 2, level: 1 }, 
    { name: "B", type: 1, level: 2 } 
] 
var types = [ 
    { description: "Type 1", id: 1 }, 
    { description: "Type 2", id: 2 } 
] 
var levels = [ 
    { description: "Level 1", id: 1 }, 
    { description: "Level 2", id: 1 } 
] 

Я хочу иметь следующий результат:

var users = [ 
    { name: "A", type: 2, level: 1, levelDescription: "Level 1", typeDescription: "Type 2" }, 
    { name: "B", type: 1, level: 2, levelDescription: "Level 2", typeDescription: "Type 1" } 
] 

Я знаю, что могу достичь его, как тот

var usersObservable = RX.Observable.fromArray(users); 
var typesObservable = Rx.Observable.fromArray(types); 
var levelsOBservable = Rx.Observable.fromArray(levels); 

var uiUsers= [];// not really needed because I will use the same users array again. 

usersObservable.map(function(user) { 
     typesObservable.filter(function(type) { 
     return type.id == user.type; 
    }).subscribeOnNext(function(userType) { 
     user.typeDescription = userType.description; 
    }); 
    return user; 
}).map(function(user) { 
     levelsOBservable.filter(function(level) { 
     return level.id == user.levelId; 
    }).subscribeOnNext(function(level) { 
     user.levelDescription = level.description; 
    }); 
    return user; 
}) 
.subscribeOnNext(function(user) { 
    uiUsers.push(user); 
}) 

Я хотел бы иметь решение без вложенных Observables.
Спасибо.

ответ

0

Я не уверен, почему вы используете Rx вообще для этой проблемы. У вас есть данные в пространстве (т. Е. Массивы), а не данные со временем (то есть наблюдаемая последовательность). Но вы вынуждаете эти массивы в Rx создавать сложное решение.

Я думаю, что вы ищете что-то вроде ответа здесь https://stackoverflow.com/a/17500836/393615, где вы бы присоединились к типам источников-источников. В вашем случае вы просто «внутреннее соединение» дважды, чтобы объединить все три набора данных.

0

Вы можете архивировать это с помощью оператора switchMap, который объединяет результат отфильтрованного потока с последним значением исходного потока и использует функцию проецирования для объединения результатов в один объект. Это может быть обобщено в вашем примере, так что вы можете использовать общую функцию более высокого порядка в обоих случаях. См. fiddle.

Полный код (ES2015, RxJS5):

const users = [ 
    { name: "A", type: 2, level: 1 }, 
    { name: "B", type: 1, level: 2 } 
]; 
const types = [ 
    { description: "Type 1", id: 1 }, 
    { description: "Type 2", id: 2 } 
]; 
const levels = [ 
    { description: "Level 1", id: 1 }, 
    { description: "Level 2", id: 2 } 
]; 

const users$ = Rx.Observable.from(users); 
const types$ = Rx.Observable.from(types); 
const levels$ = Rx.Observable.from(levels); 

function join(s$, sourceProperty, targetProperty, streamProperty) { 
    return function(initObj) { 
    const stream$ = s$.filter(x => x.id === initObj[sourceProperty]); 
    return Rx.Observable.combineLatest(
     Rx.Observable.of(initObj), 
     stream$, 
     (obj, streamObj) => { 
     const prop = streamObj[streamProperty]; 
     return Object.assign({}, obj, { [targetProperty]: prop }); 
     } 
    ); 
    }; 
} 

users$ 
    .switchMap(join(types$, 'type', 'typeDescription', 'description')) 
    .switchMap(join(levels$, 'level', 'levelDescription', 'description')) 
    .subscribe(x => console.log(x)); 
Смежные вопросы