Reduced recommended anime function complexity

This commit is contained in:
Eduard Urbach 2018-04-26 20:31:15 +02:00
parent 4f6078943c
commit 63c3ab894f
3 changed files with 95 additions and 69 deletions

View File

@ -0,0 +1,48 @@
package recommended
import (
"math"
"github.com/animenotifier/arn"
)
func getAnimeAffinity(anime *arn.Anime, animeListItem *arn.AnimeListItem, completed *arn.AnimeList, bestGenres []string) float64 {
animeAffinity := anime.Score()
// Planned anime go higher
if animeListItem != nil && animeListItem.Status == arn.AnimeListStatusPlanned {
animeAffinity += 10.0
}
// Anime whose high-ranked prequel you did not see are lower ranked
prequels := anime.Prequels()
for _, prequel := range prequels {
item := completed.Find(prequel.ID)
// Filter out unimportant prequels
if prequel.Score() < anime.Score()/2 {
continue
}
if item == nil {
animeAffinity -= 20.0
}
}
// Give favorite genre bonus if we have enough completed anime
if len(completed.Items) >= genreBonusCompletedAnimeThreshold {
bestGenreCount := 0
for _, genre := range anime.Genres {
if arn.Contains(bestGenres, genre) {
bestGenreCount++
}
}
// Use square root to dampen the bonus of additional best genres
animeAffinity += math.Sqrt(float64(bestGenreCount)) * 7.0
}
return animeAffinity
}

View File

@ -1,7 +1,6 @@
package recommended package recommended
import ( import (
"math"
"net/http" "net/http"
"sort" "sort"
@ -31,36 +30,7 @@ func Anime(ctx *aero.Context) string {
completed := animeList.FilterStatus(arn.AnimeListStatusCompleted) completed := animeList.FilterStatus(arn.AnimeListStatusCompleted)
// Genre affinity // Genre affinity
genreItems := animeList.Genres() bestGenres := getBestGenres(animeList)
genreAffinity := map[string]float64{}
bestGenres := []string{}
for genre, animeListItems := range genreItems {
affinity := 0.0
for _, item := range animeListItems {
if item.Status != arn.AnimeListStatusCompleted {
continue
}
if item.Rating.Overall != 0 {
affinity += item.Rating.Overall
} else {
affinity += 5.0
}
}
genreAffinity[genre] = affinity
bestGenres = append(bestGenres, genre)
}
sort.Slice(bestGenres, func(i, j int) bool {
return genreAffinity[bestGenres[i]] > genreAffinity[bestGenres[j]]
})
if len(bestGenres) > bestGenreCount {
bestGenres = bestGenres[:bestGenreCount]
}
// Get all anime // Get all anime
var tv []*arn.Anime var tv []*arn.Anime
@ -81,6 +51,8 @@ func Anime(ctx *aero.Context) string {
tv = append(tv, anime) tv = append(tv, anime)
} else if anime.Type == "movie" { } else if anime.Type == "movie" {
movies = append(movies, anime) movies = append(movies, anime)
} else {
continue
} }
// Skip anime from my list (except planned anime) // Skip anime from my list (except planned anime)
@ -90,44 +62,7 @@ func Anime(ctx *aero.Context) string {
continue continue
} }
animeAffinity := anime.Score() affinity[anime.ID] = getAnimeAffinity(anime, existing, completed, bestGenres)
// Planned anime go higher
if existing != nil && existing.Status == arn.AnimeListStatusPlanned {
animeAffinity += 10.0
}
// Anime whose high-ranked prequel you did not see are lower ranked
prequels := anime.Prequels()
for _, prequel := range prequels {
item := completed.Find(prequel.ID)
// Filter out unimportant prequels
if prequel.Score() < anime.Score()/2 {
continue
}
if item == nil {
animeAffinity -= 20.0
}
}
// Give favorite genre bonus if we have enough completed anime
if len(completed.Items) >= genreBonusCompletedAnimeThreshold {
bestGenreCount := 0
for _, genre := range anime.Genres {
if arn.Contains(bestGenres, genre) {
bestGenreCount++
}
}
// Use square root to dampen the bonus of additional best genres
animeAffinity += math.Sqrt(float64(bestGenreCount)) * 7.0
}
affinity[anime.ID] = animeAffinity
} }
// Sort // Sort

View File

@ -0,0 +1,43 @@
package recommended
import (
"sort"
"github.com/animenotifier/arn"
)
// getBestGenres returns the most liked genres for the user's anime list.
func getBestGenres(animeList *arn.AnimeList) []string {
genreItems := animeList.Genres()
genreAffinity := map[string]float64{}
bestGenres := []string{}
for genre, animeListItems := range genreItems {
affinity := 0.0
for _, item := range animeListItems {
if item.Status != arn.AnimeListStatusCompleted {
continue
}
if item.Rating.Overall != 0 {
affinity += item.Rating.Overall
} else {
affinity += 5.0
}
}
genreAffinity[genre] = affinity
bestGenres = append(bestGenres, genre)
}
sort.Slice(bestGenres, func(i, j int) bool {
return genreAffinity[bestGenres[i]] > genreAffinity[bestGenres[j]]
})
if len(bestGenres) > bestGenreCount {
bestGenres = bestGenres[:bestGenreCount]
}
return bestGenres
}