import numpy as np
from functools import reduce


def recall_k(ranked_list: np.ndarray, ground_truth: set):
    hits = np.sum([1.0 for iid in ranked_list if iid in ground_truth])
    return hits / len(ground_truth)


def hr_k(ranked_list: np.ndarray, ground_truth: set):
    hits = 1 if len(set(ranked_list) & ground_truth) > 0 else 0
    return hits


def precision_k(ranked_list: np.ndarray, ground_truth: set):
    hits = np.sum([1.0 for iid in ranked_list if iid in ground_truth])
    return hits / len(ranked_list)


def ndcg_k(ranked_list: np.ndarray, ground_truth: set):
    dcg = np.sum([1.0 / np.log2(i + 2) for i, iid in enumerate(ranked_list) if iid in ground_truth])
    return dcg / IDCG(min(len(ranked_list), len(ground_truth)))


def IDCG(n):
    return reduce(lambda x, y: x + 1.0 / np.log2(y + 1), range(0, n + 1))
