interface ItemRating { item : number ; rating : number ; } class ItemRatingManager { private readonly ratingsByItem : Map < number , number > = new Map ( ) ; rateItem ( item ) { const currentRating = this . ratingsByItem . get ( item ) ; this . ratingsByItem . set ( item , ( currentRating ?? 0 ) + 1 ) ; } toArray ( ) { const ratings = [ ... this . ratingsByItem . entries ( ) ] . map ( ( [ item , rating ] ) => ( { item , rating } ) ) ; return ratings ; } } export default class CollabrativeMatrix { private readonly matrix : number [ ] [ ] ; constructor ( matrix ) { this . matrix = matrix ; } filterByUser ( user ) { const manager = new ItemRatingManager ( ) ; this . forEachRatedItemByUser ( user , item => this . forEachRatedUserByItem ( item , collabrativeUser => { if ( collabrativeUser === user ) { return ; } this . forEachRatedItemByUser ( collabrativeUser , suggested => manager . rateItem ( suggested ) ) ; } ) ) ; const ratedItems = manager . toArray ( ) ; const row = this . matrix [ user ] ; return ratedItems . filter ( v => ! row [ v . item ] ) . sort ( ( x , y ) => y . rating - x . rating ) ; } private forEachRatedItemByUser ( user , callback ) { const row = this . matrix [ user ] ; for ( let item = 0 ; item < row . length ; item ++ ) { const rated = row [ item ] ; if ( rated ) { callback ( item ) ; } } } private forEachRatedUserByItem ( item , callback ) { for ( let user = 0 ; user < this . matrix . length ; user ++ ) { const rated = this . matrix [ user ] [ item ] ; if ( rated ) { callback ( user ) ; } } } }