// ----------------------------------------------------------------------
        public static string[] FilterAndSort(string search, string[] lst, float minScore)
        {
            var scores   = GetScores(search, lst);
            var ts       = P.zip(scores, lst);
            var filtered = P.filter((t) => t.Item1 > minScore, ts);

            P.sort(
                filtered,
                (t1, t2) => {
                var diff = t2.Item1 - t1.Item1;
                return(Math3D.IsZero(diff) ? 0 : (diff < 0 ? -1 : 1));
            }
                );
            return(P.map((t) => P.uncurry((score, str) => str, t), filtered));
        }
        // ----------------------------------------------------------------------
        public static string[] SortAndTake(string search, string[] lst, int maxNbOfResults)
        {
            var scores = GetScores(search, lst);
            var toSort = P.zip(scores, lst);

            P.sort(
                toSort,
                (t1, t2) => {
                var diff = t2.Item1 - t1.Item1;
                return(Math3D.IsZero(diff) ? 0 : (diff < 0 ? -1 : 1));
            }
                );
            var result = P.take(maxNbOfResults, toSort);

            return(P.map((t) => P.uncurry((score, str) => str, t), result));
        }
        // ----------------------------------------------------------------------
        public static string[] SortAndTake_(string search, string[] lst, int maxNbOfResults = 0, float minScore = 0.5f)
        {
            // Define local sort function
            Action <P.Tuple <float, string>[]> sort = (ts) => {
                P.sort(
                    ts,
                    (t1, t2) => {
                    var diff = t2.Item1 - t1.Item1;
                    return(Math3D.IsZero(diff) ? 0 : (diff < 0 ? -1 : 1));
                }
                    );
            };
            // Correctly size result.
            var len = lst.Length;

            if (maxNbOfResults == 0)
            {
                maxNbOfResults = len;
            }
            if (maxNbOfResults > len)
            {
                maxNbOfResults = len;
            }
            var result    = new P.Tuple <float, string> [maxNbOfResults];
            int resultLen = 0;
            // Filter out the input list
            bool isSorted = false;

            foreach (var l in lst)
            {
                var score = GetScore(search, l);
                if (score <= minScore)
                {
                    continue;
                }
                if (resultLen < maxNbOfResults)
                {
                    result[resultLen] = P.curry(t => P.id(t), score, l);
                    ++resultLen;
                    if (resultLen == maxNbOfResults)
                    {
                        sort(result);
                        isSorted = true;
                    }
                }
                else
                {
                    if (score > result[resultLen - 1].Item1)
                    {
                        result[resultLen - 1] = P.curry(t => P.id(t), score, l);
                        sort(result);
                        isSorted = true;
                    }
                }
                // TODO: finish SortAndTake_
            }
            // Perform a last sort in case we have not filled the max number of results.
            if (isSorted == false)
            {
                result = P.take(resultLen, result);
                sort(result);
            }
            return(P.map((t) => P.uncurry((score, str) => str, t), result));
        }