[2.0.2]AHK_Linq--Deep use of Enumerator

Post your working scripts, libraries and tools.
User avatar
Mono919
Posts: 71
Joined: 05 May 2022, 02:36

[2.0.2]AHK_Linq--Deep use of Enumerator

Post by Mono919 » 17 Mar 2023, 20:44

this library need use ptr for ahk Enumerator and Func object
update: 2023.03.21: Support 84 methods and 2 props for Enumerator. Usage is coming soon.

The ultimate goal of this library is to implement the ahk version of linq.
Here is the development progress.
More usage will present in the future.

Usage1: Select a string which length is larger than 5

Code: Select all

words := ["apple", "banana", "cherry", "date", "elderberry", "fig", "grape"]
longWords := words.asEnumerable().where(word => strlen(word) > 5)
longWords.foreach(word => msgbox(word))
Usage2: Query the square of all even numbers in an integer array

Code: Select all

numbers := [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
evenSquares := numbers.asEnumerable()
.where(number => (mod(number, 2) = 0))
.select(number => number * number)
evenSquares.foreach(square => msgbox(square))
Usage3: Query all strings starting with a in a string array and sort them by length from short to long

Code: Select all

words := ["apple", "banana", "cherry", "application", "an", "date", "elderberry", "fig", "grape"]
aWords := words.asEnumerable()
.where(word => (substr(word, 1, 1) = "a"))
.orderby(word => strlen(word))
aWords.foreach(word => msgbox(word))
Usage4: Query the names and majors of all male students over the age of 20

Code: Select all

class Student
{
    __new(Name, Age, Gender, Major)
    {
        this.Name := Name
        this.Age := Age
        this.Gender := Gender
        this.Major := Major
    }
}

class Gender
{
    static Female := 0
    static Male := 1
}

students := [Student(Name := "Alice", Age := 20, _Gender := Gender.Female, Major := "Computer Science"),
Student(Name := "Bob", Age := 22, _Gender := Gender.Male, Major := "Mathematics"),
Student(Name := "Charlie", Age := 21, _Gender := Gender.Male, Major := "Physics"),
Student(Name := "David", Age := 19, _Gender := Gender.Male, Major := "Computer Science"),
Student(Name := "Eve", Age := 20, _Gender := Gender.Female, Major := "Computer Science")]

query := students.asEnumerable().where(student => (student.Age > 20 && student.Gender = Gender.Male)).select(student => {Name: student.Name, Major: student.Major})
query.foreach(result => msgbox(result.Name " - " result.Major))
Source Code:

Code: Select all

bindGetArray := ["length", "size"]
IEnumerable.bindGet(bindGetArray)
bindCallArray := ["aggregate", "all", "any", "asEnumerable", "average", "chunk", "clone", "combination", "concat", "conflict", "contains", "count", "defaultIfEmpty", "distinct", "each", "elementAt", "elementAtOrDefault", "every", "except", "filter", "find", "findIndex", "findLast", "findLastIndex", "first", "firstOrDefault", "forEach", "groupBy", "groupJoin", "includes", "indexOf", "indices", "innerJoin", "intersect", "isSub", "isSuper", "join", "last", "lastOrDefault", "leftJoin", "leftPad", "map", "max", "maxIndex", "maxOrDefault", "min", "minIndex", "minOrDefault", "nearBy", "nearSplit", "ofType", "orderBy", "orderByDescending", "permutation", "product", "proportion", "rand", "random", "randomOrDefault", "reverse", "rightJoin", "rightPad", "select", "single", "singleOrDefault", "skip", "skipProportion", "skipSame", "skipWhile", "take", "takeProportion", "takeSame", "takeWhile", "slice", "some", "split", "sum", "toArray", "toMap", "toObject", "union", "where", "wipe", "zip"]
IEnumerable.bindCall(bindCallArray)
_ := (object.defineprop)(any.prototype, "asEnumerable", {call: Enumerable.asEnumerable.bind(Enumerable)})
_ := (object.defineprop)(string.prototype, "__enum", {call: IEnumerable.strEnum.bind(IEnumerable)})
_ := (object.defineprop)(number.prototype, "__enum", {call: IEnumerable.strEnum.bind(IEnumerable)})

class Enumerable
{
    static call(source)
    {
        return this.asEnumerable(source)
    }
    
    static asEnumerable(source)
    {
        if source is Enumerator
            return source
        try
        {
            if source.hasprop("__enum")
            {
                enum := source.__enum()
                numput("ptr", objptr(Enumerator.prototype), objptr(enum), 0x10)
                return enum
            }
            return source.ownprops()
        }
        throw typeerror("Non-iterative source.")
    }
    
    static between(start?, end?, step := 1)
    {
        _step := step
        if isset(start) && isset(end)
        {
            _start := integer(start)
            _end := integer(end)
        }
        else if isset(start)
        {
            _start := 0
            _end := integer(start)
        }
        else
            throw valueerror("at least input end number.(default start is 0 and step is 1)")
        fn(&value)
        {
            if _start <= _end
            {
                value := _start
                _start += _step
                return true
            }
            _start := fn.params[1]
            return false
        }
        this.toEnumerator(fn)
        fn.params := [_start, _end, _step]
        return fn
    }
    
    static clone(enum)
    {
        if !(enum is Enumerator)
            return enum.asEnumerable()
        try
        {
            iter := objfromptraddref(numget(objptr(enum), 5 * a_ptrsize + 0x10, "ptr")).__enum()
            numput("int", -1, objptr(iter), 6 * a_ptrsize + 0x10)
            return iter
        }
        catch
        {
            _func := objfromptraddref(numget(numget(objptr(enum), 0x10 + 5 * a_ptrsize, "ptr"), 0x10 + 11 * a_ptrsize, "ptr"))
            flag := numget(objptr(_func), 0x10 + 8 * a_ptrsize, "ptr")
            if flag
                _func := _func.bind(objfromptraddref(flag))
            if enum.hasprop("params")
                return _func(enum.params*)
            return _func()
        }
    }
    
    static from(source)
    {
        return this.asEnumerable(source)
    }
    
    static generate(generate, count := 1)
    {
        static enum := [&key1, &key2, &key3, &key4, &key5, &key6, &key7, &key8, &key9, &key10, &key11, &key12, &key13, &key14, &key15, &key16, &key17, &key18, &key19]
        iter := generate()
        fn(args*)
        {
            if args.length != count
                throw valueerror("Enumerator only support " count " outputs.")
            tmp_enum := enum.clone()
            tmp_enum.length := count
            ret := iter(tmp_enum*)
            if !ret
                return false
            for child in tmp_enum
                %args[a_index]% := %child%
            return true
        }
        this.toEnumerator(fn)
        fn.params := [generate, count]
        return fn
    }
    
    static range(start?, count?, step := 1)
    {
        _index := 0
        _step := step
        if isset(start) && isset(count)
        {
            _start := integer(start)
            _count := integer(count)
        }
        else
            throw valueerror("at least input start and count number.(default step is 1)")
        fn(&value)
        {
            if _index < _count
            {
                value := _start
                _start += _step
                _index++
                return true
            }
            _start := fn.params[1]
            _index := 0
            return false
        }
        this.toEnumerator(fn)
        fn.params := [_start, _count, _step]
        return fn
    }
    
    static repeat(element?, count?)
    {
        _index := 0
        if isset(element) && isset(count)
        {
            _element := element
            _count := integer(count)
        }
        else
            throw valueerror("please input element and count.")
        fn(&value)
        {
            if _index < _count
            {
                value := _element
                _index++
                return true
            }
            _index := 0
            return false
        }
        this.toEnumerator(fn)
        fn.params := [_element, _count]
        return fn
    }
    
    static toEnumerator(fn)
    {
        numput("ptr", objptr(Enumerator.prototype), objptraddref(fn), 0x10)
    }
}

class IEnumerable
{
    static bindCall(bindArray)
    {
        for child in bindArray
            Enumerator.prototype.defineprop(child, {call: this.%child%.bind(this)})
    }
    
    static bindGet(bindArray)
    {
        for child in bindArray
            Enumerator.prototype.defineprop(child, {get: this.%child%.bind(this)})
    }
    
    static strEnum(source)
    {
        return (array.prototype.__enum)(strsplit(source))
    }
    
    static length(source)
    {
        return [Enumerable.clone(source)*].length
    }
    
    static size(source)
    {
        return [source*].length
    }
    
    static aggregate(source, seed, func, resultSelector := "")
    {
        index := 0
        try
        {
            iter := Enumerable.clone(source)
            for element in iter
                seed := func(seed, element, index++)
        }
        catch
        {
            iter := Enumerable.clone(source)
            for element in iter
                seed := func(seed, element)
        }
        return resultSelector ? resultSelector(seed) : seed
    }
    
    static all(source, predicate := "")
    {
        index := 1
        if !predicate
        {
            iter := Enumerable.clone(source)
            for element in iter
            {
                if !isset(element)
                    return false
            }
            return true
        }
        try
        {
            iter := Enumerable.clone(source)
            for element in iter
            {
                if !predicate(element, index++)
                    return false
            }
        }
        catch
        {
            iter := Enumerable.clone(source)
            for element in iter
            {
                if !predicate(element)
                    return false
            }
        }
        return true
    }
    
    static any(source, predicate := "")
    {
        index := 1
        if !predicate
        {
            iter := Enumerable.clone(source)
            for element in iter
            {
                if isset(element)
                    return true
            }
            return false
        }
        try
        {
            iter := Enumerable.clone(source)
            for element in iter
            {
                if predicate(element, index++)
                    return true
            }
        }
        catch
        {
            iter := Enumerable.clone(source)
            for element in iter
            {
                if predicate(element)
                    return true
            }
        }
        return false
    }
    
    static asEnumerable(source)
    {
        return source
    }
    
    static average(source, selector := "")
    {
        sum := 0
        index := 1
        count := 0
        if !selector
        {
            iter := Enumerable.clone(source)
            for element in iter
            {
                sum += element
                if string(sum) = "inf" || string(sum) = "nan"
                    return sum
                count++
            }
            return sum / count
        }
        try
        {
            iter := Enumerable.clone(source)
            for element in iter
            {
                sum += selector(element, index++)
                if string(sum) = "inf" || string(sum) = "nan"
                    return sum
                count++
            }
        }
        catch
        {
            iter := Enumerable.clone(source)
            for element in iter
            {
                sum += selector(element)
                if string(sum) = "inf" || string(sum) = "nan"
                    return sum
                count++
            }
        }
        return sum / count
    }
    
    static chunk(source, chunk, offset := 0)
    {
        static enum := [&key1, &key2, &key3, &key4, &key5, &key6, &key7, &key8, &key9, &key10, &key11, &key12, &key13, &key14, &key15, &key16, &key17, &key18, &key19]
        offset := offset < 0 ? mod((mod(offset, chunk) + chunk), chunk) : offset
        index := 1
        iter := Enumerable.clone(source)
        tmp_enum := enum.clone()
        tmp_enum.length := iter.minparams
        loop offset
            iter(tmp_enum*)
        fn(&_iter)
        {
            array_enum := []
            tmp_enum := enum.clone()
            tmp_enum.length := iter.maxparams
            loop chunk
            {
                tmp_array := []
                ret := iter(tmp_enum*)
                if !ret
                    break
                for child in tmp_enum
                    tmp_array.push(%child%)
                array_enum.push(tmp_array.__enum())
            }
            if !array_enum.length
                return false
            array_enum := array_enum.__enum()
            _iter := this.chunk_base(array_enum)
            return true
        }
        Enumerable.toEnumerator(fn)
        fn.params := [source, chunk, offset]
        return fn
    }
    
    static chunk_base(array_enum)
    {
        static enum := [&key1, &key2, &key3, &key4, &key5, &key6, &key7, &key8, &key9, &key10, &key11, &key12, &key13, &key14, &key15, &key16, &key17, &key18, &key19]
        fn(args*)
        {
            count := args.length
            tmp_enum := enum.clone()
            tmp_enum.length := count
            ret := array_enum(&value)
            if !ret
                return false
            loop count
                %args[a_index]% := (value(&_value), _value)
            return true
        }
        Enumerable.toEnumerator(fn)
        fn.params := [Enumerable.clone(array_enum)]
        return fn
    }
    
    static clone(source)
    {
        return Enumerable.clone(source)
    }
    
    static combination(source, count, repeatable := false)
    {
        length := this.length(source)
        iter_pos := []
        now_pos := []
        max_pos := []
        value_pos := []
        loop count
        {
            now_pos.push(1)
            max_pos.push(length)
            enum := Enumerable.clone(source)
            iter_pos.push(enum)
            if a_index != count
            {
                enum(&value)
                value_pos.push(value)
            }
            else
                value_pos.push("")
        }
        now_pos[-1] := 0
        fn(&_iter)
        {
            point := count
            modify := 1
            while (point > 0)
            {
                now_pos[point] += modify
                modify := now_pos[point] // (max_pos[point] + 1)
                if !modify
                {
                    iter_pos[point](&value)
                    value_pos[point] := value
                    break
                }
                now_pos[point] := mod(now_pos[point], max_pos[point])
                enum := Enumerable.clone(source)
                iter_pos[point] := enum
                enum(&value)
                value_pos[point] := value
                point--
            }
            if point <= 0
                return false
            if !corr_array(now_pos)
                return fn(&_iter)
            else
                _iter := value_pos.clone().__enum()
            return true
            
            corr_array(_array)
            {
                if _array.length <= 1
                    return true
                enum := _array.__enum()
                enum(&first)
                for child in enum
                {
                    if repeatable
                    {
                        if child < first
                            return false
                    }
                    else
                    {
                        if child <= first
                            return false
                    }
                    first := child
                }
                return true
            }
        }
        Enumerable.toEnumerator(fn)
        fn.params := [source, count, repeatable]
        return fn
    }
    
    static concat(source, other*)
    {
        static enum := [&key1, &key2, &key3, &key4, &key5, &key6, &key7, &key8, &key9, &key10, &key11, &key12, &key13, &key14, &key15, &key16, &key17, &key18, &key19]
        new_iter := [Enumerable.clone(source)]
        for _iter in other
            new_iter.push(Enumerable.clone(_iter))
        index := 1
        length := new_iter.length
        fn(args*)
        {
            tmp_enum := enum.clone()
            tmp_enum.length := args.length
            if !new_iter[index](tmp_enum*)
            {
                if index = length
                    return false
                index++
                return fn(args*)
            }
            for child in tmp_enum
                %args[a_index]% := %child%
            return true
        }
        Enumerable.toEnumerator(fn)
        fn.params := [source, other*]
        return fn
    }
    
    static conflict(source, selector := "", comparer := (key, other) => key = other)
    {
        index := 1
        temp := []
        if !selector
        {
            iter := Enumerable.clone(source)
            for element in iter
            {
                key := element
                for other in temp
                {
                    if comparer(key, other)
                        return true
                }
                temp.push(key)
            }
            return false
        }
        try
        {
            iter := Enumerable.clone(source)
            for element in iter
            {
                key := selector(element, index++)
                for other in temp
                {
                    if comparer(key, other)
                        return true
                }
                temp.push(key)
            }
        }
        catch
        {
            iter := Enumerable.clone(source)
            for element in iter
            {
                key := selector(element)
                for other in temp
                {
                    if comparer(key, other)
                        return true
                }
                temp.push(key)
            }
        }
        return false
    }
    
    static contains(source, value, comparer := (key, other) => key = other)
    {
        iter := Enumerable.clone(source)
        for element in iter
        {
            if comparer(element, value)
                return true
        }
        return false
    }
    
    static count(source, predicate := "")
    {
        if !predicate
            return this.length(source)
        index := 1
        count := 0
        try
        {
            iter := Enumerable.clone(source)
            for element in iter
            {
                if predicate(element, index++)
                    count++
            }
        }
        catch
        {
            iter := Enumerable.clone(source)
            for element in iter
            {
                if predicate(element)
                    count++
            }
        }
        return count
    }
    
    static defaultIfEmpty(source, defaultValue)
    {
        if !this.length(source)
            return [defaultValue].__enum()
        return source
    }
    
    static distinct(source, comparer := (key, other) => key = other)
    {
        temp := []
        iter := Enumerable.clone(source)
        fn(&value)
        {
            if !iter(&element)
                return false
            key := element
            for other in temp
            {
                if comparer(key, other)
                    return fn(&value)
            }
            value := key
            temp.push(key)
            return true
        }
        Enumerable.toEnumerator(fn)
        fn.params := [source, comparer]
        return fn
    }
    
    static each(source, action := "")
    {
        static enum := [&key1, &key2, &key3, &key4, &key5, &key6, &key7, &key8, &key9, &key10, &key11, &key12, &key13, &key14, &key15, &key16, &key17, &key18, &key19]
        if !action
            return source
        fn(args*)
        {
            tmp_enum := enum.clone()
            tmp_enum.length := args.length
            if !source(tmp_enum*)
                return false
            for child in tmp_enum
                %args[a_index]% := action(%child%)
            return true
        }
        Enumerable.toEnumerator(fn)
        fn.params := [source, action]
        return fn
    }
    
    static elementAt(source, index)
    {
        tmp_index := index
        iter := Enumerable.clone(source)
        for element in iter
        {
            if index-- == 1
                return element
        }
        throw valueerror("input index " tmp_index " is out of range.")
    }
    
    static elementAtOrDefault(source, index, defaultValue)
    {
        iter := Enumerable.clone(source)
        for element in iter
        {
            if index-- == 1
                return element
        }
        return defaultValue
    }
    
    static every(source, callback, thisArg*)
    {
        try
            return this.all(source, (element, index) => callback.bind(thisArg*)(element, index))
        catch
            return this.all(source, (element, index) => callback.bind(thisArg*)(element))
    }
    
    static except(source, other, comparer := (key, other) => key = other)
    {
        temp := []
        others := other
        iter := Enumerable.clone(source)
        fn(&value)
        {
            if !iter(&element)
                return false
            key := element
            for other in Enumerable.clone(others)
            {
                if comparer(key, other)
                    return fn(&value)
            }
            for other in temp
            {
                if comparer(key, other)
                    return fn(&value)
            }
            value := key
            temp.push(key)
            return true
        }
        Enumerable.toEnumerator(fn)
        fn.params := [source, other, comparer]
        return fn
    }
    
    static filter(source, callback, thisArg*)
    {
        try
            return this.where(source, (element, index) => callback.bind(thisArg*)(element, index))
        catch
            return this.where(source, (element, index) => callback.bind(thisArg*)(element))
    }
    
    static find(source, callback, thisArg*)
    {
        try
            return this.first(source, (element, index) => callback.bind(thisArg*)(element, index))
        catch
            return this.first(source, (element, index) => callback.bind(thisArg*)(element))
    }
    
    static findIndex(source, callback, thisArg*)
    {
        index := 1
        try
        {
            iter := Enumerable.clone(source)
            for element in iter
            {
                if callback.bind(thisArg*)(element, index)
                    return index
                index++
            }
        }
        catch
        {
            iter := Enumerable.clone(source)
            for element in iter
            {
                if callback.bind(thisArg*)(element)
                    return index
                index++
            }
        }
        return -1
    }
    
    static findLast(source, callback, thisArg*)
    {
        try
            return this.last(source, (element, index) => callback.bind(thisArg*)(element, index))
        catch
            return this.last(source, (element, index) => callback.bind(thisArg*)(element))
    }
    
    static findLastIndex(source, callback, thisArg*)
    {
        tmp_index := -1
        index := 1
        try
        {
            iter := Enumerable.clone(source)
            for element in iter
            {
                if callback.bind(thisArg*)(element, index)
                    tmp_index := index
                index++
            }
        }
        catch
        {
            iter := Enumerable.clone(source)
            for element in iter
            {
                if callback.bind(thisArg*)(element)
                    tmp_index := index
                index++
            }
        }
        return tmp_index
    }
    
    static first(source, predicate := "")
    {
        index := 1
        if !predicate
        {
            iter := Enumerable.clone(source)
            for element in iter
            {
                if isset(element)
                    return element
            }
            throw valueerror("Cannot find value.")
        }
        try
        {
            iter := Enumerable.clone(source)
            for element in iter
            {
                if predicate(element, index++)
                    return element
            }
        }
        catch
        {
            iter := Enumerable.clone(source)
            for element in iter
            {
                if predicate(element)
                    return element
            }
        }
        throw valueerror("Cannot find value.")
    }
    
    static firstOrDefault(source, defalutValue, predicate := "")
    {
        index := 1
        if !predicate
        {
            iter := Enumerable.clone(source)
            for element in iter
            {
                if isset(element)
                    return element
            }
            return defalutValue
        }
        try
        {
            iter := Enumerable.clone(source)
            for element in iter
            {
                if predicate(element, index++)
                    return element
            }
        }
        catch
        {
            iter := Enumerable.clone(source)
            for element in iter
            {
                if predicate(element)
                    return element
            }
        }
        return defalutValue
    }
    
    static forEach(source, action, thisArg*)
    {
        index := 1
        try
        {
            iter := Enumerable.clone(source)
            for element in iter
                action.bind(thisArg*)(element, index++)
        }
        catch
        {
            iter := Enumerable.clone(source)
            for element in iter
                action.bind(thisArg*)(element)
        }
    }
    
    static groupBy(source, keySelector := (key) => key, elementSelector := (element) => element, resultSelector := (result) => result, comparer := (key, other) => key = other)
    {
        keymap := map()
        iter := Enumerable.clone(source)
        for element in iter
        {
            key := keySelector(element)
            truekey := this.firstOrDefault(this.where(keymap.__enum(), comparer.bind(key)), "")
            if truekey = ""
                keymap[key] := [elementSelector(element)]
            else
                keymap[truekey].push(elementSelector(element))
        }
        enum := keymap.__enum()
        fn(&_iter)
        {
            if !enum(&key, &value)
                return false
            try
                _iter := resultSelector(key, value.__enum())
            catch
                _iter := resultSelector([key, value.__enum()].__enum())
            return true
        }
        Enumerable.toEnumerator(fn)
        fn.params := [source, keySelector, elementSelector, resultSelector, comparer]
        return fn
    }
    
    static groupJoin(source, inner, resultSelector := (key, result) => result, outerKeySelector := (key) => key, innerKeySelector := (key) => key, comparer := (key, other) => key = other)
    {
        iter := this.groupBy(source, outerKeySelector, , (key, value) => [key, value])
        inner_iter := this.groupBy(inner, innerKeySelector, , (key, value) => [key, value])
        fn(&_iter)
        {
            if !iter(&key_value)
                return false
            tmp_iter := Enumerable.clone(inner_iter)
            for _key_value in tmp_iter
            {
                if comparer(key_value[1], _key_value[1])
                {
                    _iter := resultSelector(key_value[1], _key_value[2])
                    return true
                }
            }
            return fn(&_iter)
        }
        Enumerable.toEnumerator(fn)
        fn.params := [source, inner, resultSelector, outerKeySelector, innerKeySelector, comparer]
        return fn
    }
    
    static includes(source, element, start := 0)
    {
        comparer := (key, other) => key = other
        iter := Enumerable.skip(source, start)
        for _element in iter
        {
            if comparer(element, _element)
                return true
        }
        return false
    }
    
    static indexOf(source, element, start := 0, comparer := (key, other) => key = other)
    {
        index := 1
        iter := Enumerable.skip(source, start)
        for _element in iter
        {
            if comparer(element, _element)
                return index
            index++
        }
        return -1
    }
    
    static indices(source, indices)
    {
        iter := Enumerable.clone(indices)
        fn(&value)
        {
            if !iter(&element)
                return false
            value := this.elementAt(source, element)
            return true
        }
        Enumerable.toEnumerator(fn)
        fn.params := [source, indices]
        return fn
    }
    
    static innerJoin(source, inner, resultSelector := (key, result) => result, outerKeySelector := (key) => key, innerKeySelector := (key) => key, comparer := (key, other) => key = other)
    {
        iter := Enumerable.clone(source)
        inner_iter := Enumerable.clone(inner)
        fn(&_iter)
        {
            if !isset(element) && !iter(&element)
                return false
            key := outerKeySelector(element)
            while inner_iter(&inner_element)
            {
                if comparer(key, innerKeySelector(inner_element))
                {
                    _iter := [element, inner_element].__enum()
                    return true
                }
            }
            element := unset
            inner_iter := Enumerable.clone(inner)
            return fn(&_iter)
        }
        Enumerable.toEnumerator(fn)
        fn.params := [source, inner, resultSelector, outerKeySelector, innerKeySelector, comparer]
        return fn
    }
    
    static intersect(source, other, comparer := (key, other) => key = other)
    {
        temp := []
        others := other
        iter := Enumerable.clone(source)
        fn(&value)
        {
            if !iter(&element)
                return false
            key := element
            for other in Enumerable.clone(others)
            {
                if comparer(key, other)
                {
                    for _other in temp
                    {
                        if comparer(key, _other)
                            continue 2
                    }
                    value := key
                    temp.push(key)
                    return true
                }
            }
            return fn(&value)
        }
        Enumerable.toEnumerator(fn)
        fn.params := [source, other, comparer]
        return fn
    }
    
    static isSub(source, other, comparer := (key, other) => key = other)
    {
        iter := Enumerable.clone(source)
        for element in iter
        {
            if !this.contains(other, element, comparer)
                return false
        }
        return true
    }
    
    static isSuper(source, other, comparer := (key, other) => key = other)
    {
        iter := Enumerable.clone(other)
        for element in iter
        {
            if !this.contains(source, element, comparer)
                return false
        }
        return true
    }
    
    static join(source, inner, resultSelector := (key, result) => result, outerKeySelector := (key) => key, innerKeySelector := (key) => key, comparer := (key, other) => key = other)
    {
        iter := Enumerable.clone(source)
        inner_iter := Enumerable.clone(inner)
        fn(&_iter)
        {
            if !isset(element) && !iter(&element)
                return false
            key := outerKeySelector(element)
            while inner_iter(&inner_element)
            {
                if comparer(key, innerKeySelector(inner_element))
                {
                    _iter := [element, inner_element].__enum()
                    return true
                }
            }
            element := unset
            inner_iter := Enumerable.clone(inner)
            return fn(&_iter)
        }
        Enumerable.toEnumerator(fn)
        fn.params := [source, inner, resultSelector, outerKeySelector, innerKeySelector, comparer]
        return fn
    }
    
    static last(source, predicate := "")
    {
        index := 1
        if !predicate
        {
            iter := Enumerable.clone(source)
            for element in iter
            {
                if isset(element)
                    tmp_element := element
            }
            if !isset(tmp_element)
                throw valueerror("Cannot find value.")
            return tmp_element
        }
        try
        {
            iter := Enumerable.clone(source)
            for element in iter
            {
                if predicate(element, index++)
                    tmp_element := element
            }
        }
        catch
        {
            iter := Enumerable.clone(source)
            for element in iter
            {
                if predicate(element)
                    tmp_element := element
            }
        }
        if !isset(tmp_element)
            throw valueerror("Cannot find value.")
        return tmp_element
    }
    
    static lastOrDefault(source, defalutValue, predicate := "")
    {
        index := 1
        if !predicate
        {
            iter := Enumerable.clone(source)
            for element in iter
            {
                if isset(element)
                    tmp_element := element
            }
            if !isset(tmp_element)
                return defalutValue
            return tmp_element
        }
        try
        {
            iter := Enumerable.clone(source)
            for element in iter
            {
                if predicate(element, index++)
                    tmp_element := element
            }
        }
        catch
        {
            iter := Enumerable.clone(source)
            for element in iter
            {
                if predicate(element)
                    tmp_element := element
            }
        }
        if !isset(tmp_element)
            return defalutValue
        return tmp_element
    }
    
    static leftJoin(source, inner, resultSelector := (key, result) => result, outerKeySelector := (key) => key, innerKeySelector := (key) => key, comparer := (key, other) => key = other)
    {
        iter := Enumerable.clone(source)
        inner_iter := Enumerable.clone(inner)
        fn(&_iter)
        {
            if !isset(element)
            {
                if !iter(&element)
                    return false
                flag := false
            }
            key := outerKeySelector(element)
            while inner_iter(&inner_element)
            {
                if comparer(key, innerKeySelector(inner_element))
                {
                    _iter := [element, inner_element].__enum()
                    flag := true
                    return true
                }
            }
            if !flag
            {
                _iter := [element, ].__enum()
                element := unset
                return true
            }
            element := unset
            inner_iter := Enumerable.clone(inner)
            return fn(&_iter)
        }
        Enumerable.toEnumerator(fn)
        fn.params := [source, inner, resultSelector, outerKeySelector, innerKeySelector, comparer]
        return fn
    }
    
    static leftPad(source, length, value)
    {
        index := 1
        _length := this.length(source)
        iter := Enumerable.clone(source)
        tmp_length := length - _length
        if tmp_length <= 0
            return source
        fn(&element)
        {
            if index > length
                return false
            if index <= tmp_length
            {
                element := value
                index++
                return true
            }
            iter(&element)
            index++
            return true
        }
        Enumerable.toEnumerator(fn)
        fn.params := [source, length, value]
        return fn
    }
    
    static map(source, callback, thisArg*)
    {
        try
            return this.select(source, (element, index) => callback.bind(thisArg*)(element, index))
        catch
            return this.select(source, (element, index) => callback.bind(thisArg*)(element))
    }
    
    static max(source, selector := (value) => value, comparer := (key, other) => (key > other) ? 1 : (key < other) ? -1 : 0)
    {
        node := this.maxNode(source, selector, comparer)
        return node.element
    }
    
    static maxIndex(source, selector := (value) => value, comparer := (key, other) => (key > other) ? 1 : (key < other) ? -1 : 0)
    {
        try
            node := this.maxNode(source, selector, comparer)
        catch
            return -1
        return node.index
    }
    
    static maxNode(source, selector, comparer)
    {
        index := 1
        try
        {
            iter := Enumerable.clone(source)
            for element in iter
            {
                if !isset(maxNode)
                    maxNode := {element: element, index: index, value: selector(element, index)}
                else
                {
                    index++
                    value := selector(element, index)
                    if comparer(maxNode.value, value) <= 0
                    {
                        maxNode.element := element
                        maxNode.index := index
                        maxNode.value := value
                    }
                }
            }
        }
        catch
        {
            iter := Enumerable.clone(source)
            for element in iter
            {
                if !isset(maxNode)
                    maxNode := {element: element, index: index, value: selector(element)}
                else
                {
                    index++
                    value := selector(element)
                    if comparer(maxNode.value, value) <= 0
                    {
                        maxNode.element := element
                        maxNode.index := index
                        maxNode.value := value
                    }
                }
            }
        }
        if !isset(maxNode)
            throw valueerror("Empty Enumerator")
        return maxNode
    }
    
    static maxOrDefault(source, defaultValue, selector := (value) => value, comparer := (key, other) => (key > other) ? 1 : (key < other) ? -1 : 0)
    {
        try
            node := this.maxNode(source, selector, comparer)
        catch
            return defaultValue
        return node.element
    }
    
    static min(source, selector := (value) => value, comparer := (key, other) => (key > other) ? 1 : (key < other) ? -1 : 0)
    {
        node := this.minNode(source, selector, comparer)
        return node.element
    }
    
    static minIndex(source, selector := (value) => value, comparer := (key, other) => (key > other) ? 1 : (key < other) ? -1 : 0)
    {
        try
            node := this.minNode(source, selector, comparer)
        catch
            return -1
        return node.index
    }
    
    static minNode(source, selector, comparer)
    {
        index := 1
        try
        {
            iter := Enumerable.clone(source)
            for element in iter
            {
                if !isset(minNode)
                    minNode := {element: element, index: index, value: selector(element, index)}
                else
                {
                    index++
                    value := selector(element, index)
                    if comparer(minNode.value, value) >= 0
                    {
                        minNode.element := element
                        minNode.index := index
                        minNode.value := value
                    }
                }
            }
        }
        catch
        {
            iter := Enumerable.clone(source)
            for element in iter
            {
                if !isset(minNode)
                    minNode := {element: element, index: index, value: selector(element)}
                else
                {
                    index++
                    value := selector(element)
                    if comparer(minNode.value, value) >= 0
                    {
                        minNode.element := element
                        minNode.index := index
                        minNode.value := value
                    }
                }
            }
        }
        if !isset(minNode)
            throw valueerror("Empty Enumerator")
        return minNode
    }
    
    static minOrDefault(source, defaultValue, selector := (value) => value, comparer := (key, other) => (key > other) ? 1 : (key < other) ? -1 : 0)
    {
        try
            node := this.minNode(source, selector, comparer)
        catch
            return defaultValue
        return node.element
    }
    
    static nearBy(source, keySelector := (key) => key, elementSelector := (element) => element, resultSelector := (result) => result, comparer := (key, other) => key = other)
    {
        keymap := map()
        iter := Enumerable.clone(source)
        for element in iter
        {
            key := keySelector(element)
            if !isset(last_key)
            {
                last_key := key
                keymap[last_key] := [elementSelector(element)]
                continue
            }
            if comparer(key, last_key)
                keymap[last_key].push(elementSelector(element))
            else
            {
                last_key := key
                keymap[last_key] := [elementSelector(element)]
            }
        }
        enum := keymap.__enum()
        fn(&_iter)
        {
            if !enum(&key, &value)
                return false
            try
                _iter := resultSelector(key, value.__enum())
            catch
                _iter := resultSelector([key, value.__enum()].__enum())
            return true
        }
        Enumerable.toEnumerator(fn)
        fn.params := [source, keySelector, elementSelector, resultSelector, comparer]
        return fn
    }
    
    static nearSplit(source, splitPredicate)
    {
        index := 1
        next_empty := false
        iter := Enumerable.clone(source)
        fn(&_iter)
        {
            if isset(splitflag) && !splitflag
                return false
            splitflag := false
            if next_empty
            {
                next_empty := false
                _iter := [].__enum()
                return true
            }
            if !iter(&element)
                return false
            try
            {
                if splitPredicate(element, index++)
                    array_enum := [element]
                else
                {
                    _iter := [].__enum()
                    return true
                }
                while iter(&element)
                {
                    if !splitPredicate(element, index++)
                    {
                        splitflag := true
                        break
                    }
                    array_enum.push(element)
                }
            }
            catch
            {
                if splitPredicate(element)
                    array_enum := [element]
                else
                {
                    _iter := [].__enum()
                    return true
                }
                while iter(&element)
                {
                    if !splitPredicate(element)
                    {
                        splitflag := true
                        break
                    }
                    array_enum.push(element)
                }
            }
            _iter := array_enum.__enum()
            next_empty := splitflag ? true : false
            return true
        }
        Enumerable.toEnumerator(fn)
        fn.params := [source, splitPredicate]
        return fn
    }
    
    static ofType(source, type)
    {
        iter := Enumerable.clone(source)
        fn(&value)
        {
            if !iter(&element)
                return false
            if element is type
            {
                value := element
                return true
            }
            else
                return fn(&value)
        }
        Enumerable.toEnumerator(fn)
        fn.params := [source, type]
        return fn
    }
    
    static orderBy(source, keySelector := (key) => key, comparer := (key, other) => (key > other) ? 1 : (key < other) ? -1 : 0)
    {
        array_enum := this.toArray(source)
        QuickSort(array_enum, 1, array_enum.length)
        return array_enum.__enum()
        QuickSort(arr, left, right)
        {
            if (left < right)
            {
                pivotIndex := Partition(arr, left, right)
                QuickSort(arr, left, pivotIndex - 1)
                QuickSort(arr, pivotIndex + 1, right)
            }
        }
        Partition(arr, left, right)
        {
            pivot := keySelector(arr[left])
            i := left + 1
            j := right
            while (i <= j)
            {
                while (i <= j && comparer(keySelector(arr[i]), pivot) <= 0)
                    i++
                while (i <= j && comparer(keySelector(arr[j]), pivot) > 0)
                    j--
                if (i < j)
                {
                    temp := arr[i]
                    arr[i] := arr[j]
                    arr[j] := temp
                }
            }
            temp := arr[left]
            arr[left] := arr[j]
            arr[j] := temp
            return j
        }
    }
    
    static orderByDescending(source, keySelector := (key) => key, comparer := (key, other) => (key > other) ? 1 : (key < other) ? -1 : 0)
    {
        array_enum := this.toArray(source)
        QuickSort(array_enum, 1, array_enum.length)
        return array_enum.__enum()
        QuickSort(arr, left, right)
        {
            if (left < right)
            {
                pivotIndex := Partition(arr, left, right)
                QuickSort(arr, left, pivotIndex - 1)
                QuickSort(arr, pivotIndex + 1, right)
            }
        }
        Partition(arr, left, right)
        {
            pivot := keySelector(arr[left])
            i := left + 1
            j := right
            while (i <= j)
            {
                while (i <= j && comparer(keySelector(arr[i]), pivot) >= 0)
                    i++
                while (i <= j && comparer(keySelector(arr[j]), pivot) < 0)
                    j--
                if (i < j)
                {
                    temp := arr[i]
                    arr[i] := arr[j]
                    arr[j] := temp
                }
            }
            temp := arr[left]
            arr[left] := arr[j]
            arr[j] := temp
            return j
        }
    }
    
    static permutation(source, count, repeatable := false)
    {
        length := this.length(source)
        iter_pos := []
        now_pos := []
        max_pos := []
        value_pos := []
        loop count
        {
            now_pos.push(1)
            max_pos.push(length)
            enum := Enumerable.clone(source)
            iter_pos.push(enum)
            if a_index != count
            {
                enum(&value)
                value_pos.push(value)
            }
            else
                value_pos.push("")
        }
        now_pos[-1] := 0
        fn(&_iter)
        {
            point := count
            modify := 1
            while (point > 0)
            {
                now_pos[point] += modify
                modify := now_pos[point] // (max_pos[point] + 1)
                if !modify
                {
                    iter_pos[point](&value)
                    value_pos[point] := value
                    break
                }
                now_pos[point] := mod(now_pos[point], max_pos[point])
                enum := Enumerable.clone(source)
                iter_pos[point] := enum
                enum(&value)
                value_pos[point] := value
                point--
            }
            if point <= 0
                return false
            if !repeatable && !corr_array(now_pos)
                return fn(&_iter)
            else
                _iter := value_pos.clone().__enum()
            return true
            
            corr_array(_array)
            {
                tmp_map := map()
                if _array.length <= 1
                    return true
                enum := _array.__enum()
                for child in enum
                {
                    if tmp_map.has(child)
                        return false
                    else
                        tmp_map[child] := ""
                }
                return true
            }
        }
        Enumerable.toEnumerator(fn)
        fn.params := [source, count, repeatable]
        return fn
    }
    
    static product(source, selector := "")
    {
        prod := 0
        index := 1
        if !selector
        {
            iter := Enumerable.clone(source)
            for element in iter
            {
                prod *= element
                if string(prod) = "inf" || string(prod) = "nan"
                    return prod
            }
            return prod
        }
        try
        {
            iter := Enumerable.clone(source)
            for element in iter
            {
                prod *= selector(element, index++)
                if string(prod) = "inf" || string(prod) = "nan"
                    return prod
            }
        }
        catch
        {
            iter := Enumerable.clone(source)
            for element in iter
            {
                prod *= selector(element)
                if string(prod) = "inf" || string(prod) = "nan"
                    return prod
            }
        }
        return prod
    }
    
    static proportion(source, predicate := "")
    {
        index := 1
        count := 0
        total := this.length(source)
        if !total
            return 1
        if !predicate
        {
            iter := Enumerable.clone(source)
            for element in iter
            {
                if isset(element)
                    count++
            }
            return count / total
        }
        try
        {
            iter := Enumerable.clone(source)
            for element in iter
            {
                if predicate(element, index++)
                    count++
            }
        }
        catch
        {
            iter := Enumerable.clone(source)
            for element in iter
            {
                if predicate(element)
                    count++
            }
        }
        return count / total
    }
    
    static rand(source, count := 0)
    {
        length := this.length(source)
        array_enum := []
        if !count
        {
            loop length
                array_enum.push(a_index)
            loop length
            {
                rand := random(1, length)
                tmp := array_enum[a_index]
                array_enum[a_index] := array_enum[rand]
                array_enum[rand] := tmp
            }
        }
        else
        {
            loop count
            {
                rand := random(1, length)
                array_enum.push(rand)
            }
        }
        array_enum := array_enum.__enum()
        fn(&value)
        {
            if !array_enum(&index)
                return false
            iter := Enumerable.clone(source)
            loop index - 1
                iter(&element)
            iter(&value)
            return true
        }
        Enumerable.toEnumerator(fn)
        fn.params := [source, count]
        return fn
    }
    
    static random(source)
    {
        length := this.length(source)
        if !length
            throw valueerror("Empty Enumerator")
        rand := random(1, length)
        iter := Enumerable.clone(source)
        loop rand
            iter(&element)
        return element
    }
    
    static randomOrDefault(source, defaultValue)
    {
        length := this.length(source)
        if !length
            return defaultValue
        rand := random(1, length)
        iter := Enumerable.clone(source)
        loop rand
            iter(&element)
        return element
    }
    
    static reduce(source, callback, initialValue)
    {
        try
            return this.aggregate(source, initialValue, (seed, element, index) => callback(seed, element, index))
        catch
            return this.aggregate(source, initialValue, (seed, element, index) => callback(seed, element))
    }
    
    static reduceRight(source, callback, initialValue)
    {
        try
            return this.reverse(source).aggregate(source, initialValue, (seed, element, index) => callback(seed, element, index))
        catch
            return this.reverse(source).aggregate(source, initialValue, (seed, element, index) => callback(seed, element))
    }
    
    static reverse(source)
    {
        array_enum := this.toArray(array_enum)
        new_enum := []
        for element in array_enum
            new_enum.insertat(1, element)
        return new_enum.__enum()
    }
    
    static rightJoin(source, inner, resultSelector := (key, result) => result, outerKeySelector := (key) => key, innerKeySelector := (key) => key, comparer := (key, other) => key = other)
    {
        iter := Enumerable.clone(source)
        inner_iter := Enumerable.clone(inner)
        fn(&_iter)
        {
            if !isset(inner_element)
            {
                if !inner_iter(&inner_element)
                    return false
                flag := false
            }
            key := innerKeySelector(inner_element)
            while iter(&element)
            {
                if comparer(key, outerKeySelector(element))
                {
                    _iter := [element, inner_element].__enum()
                    flag := true
                    return true
                }
            }
            if !flag
            {
                _iter := [, inner_element].__enum()
                element := unset
                return true
            }
            inner_element := unset
            iter := Enumerable.clone(source)
            return fn(&_iter)
        }
        Enumerable.toEnumerator(fn)
        fn.params := [source, inner, resultSelector, outerKeySelector, innerKeySelector, comparer]
        return fn
    }
    
    static rightPad(source, length, value)
    {
        index := 1
        _length := this.length(source)
        iter := Enumerable.clone(source)
        if _length >= length
            return source
        fn(&element)
        {
            if index > length
                return false
            if index > _length
            {
                element := value
                index++
                return true
            }
            iter(&element)
            index++
            return true
        }
        Enumerable.toEnumerator(fn)
        fn.params := [source, length, value]
        return fn
    }
    
    static select(source, selector := (value) => value)
    {
        iter := Enumerable.clone(source)
        fn(&value)
        {
            if !iter(&element)
                return false
            value := selector(element)
            return true
        }
        Enumerable.toEnumerator(fn)
        fn.params := [source, selector]
        return fn
    }
    
    static sequenceEqual(source, other, comparer := (key, other) => key = other)
    {
        iter_length := this.length(source)
        other_iter_length := this.length(other)
        if iter_length != other_iter_length
            return false
        iter := Enumerable.clone(source)
        other_iter := Enumerable.clone(other)
        loop iter_length
        {
            iter(&element)
            other_iter(&_element)
            if !comparer(element, _element)
                return false
        }
        return true
    }
    
    static single(source, predicate := "")
    {
        return this.singleNode(source, predicate).element
    }
    
    static singleOrDefault(source, defaultValue, predicate := "")
    {
        try
            return this.singleNode(source, predicate).element
        return defaultValue
    }
    
    static singleNode(source, predicate)
    {
        index := 1
        if !predicate
        {
            iter := Enumerable.clone(source)
            for element in iter
            {
                if isset(element)
                {
                    if isset(single)
                        throw valueerror("Too many elements find in Enumerator.")
                    single := {element: element, index: index}
                }
                index++
            }
            if !isset(single)
                throw valueerror("No such element in Enumerator.")
            return single
        }
        try
        {
            iter := Enumerable.clone(source)
            for element in iter
            {
                if predicate(element, index)
                {
                    if isset(single)
                        throw valueerror("Too many elements find in Enumerator")
                    single := {element: element, index: index}
                }
                index++
            }
        }
        catch
        {
            iter := Enumerable.clone(source)
            for element in iter
            {
                if predicate(element)
                {
                    if isset(single)
                        throw valueerror("Too many elements find in Enumerator")
                    single := {element: element, index: index}
                }
                index++
            }
        }
        if !isset(single)
            throw valueerror("No such element in Enumerator.")
        return single
    }
    
    static skip(source, count)
    {
        length := this.length(source)
        if count > length
            return [].__enum()
        if count <= 0
            return Enumerable.clone(source)
        iter := Enumerable.clone(source)
        loop count
            iter(&value)
        return iter
    }
    
    static skipProportion(source, proportion)
    {
        length := this.length(source)
        count := floor(proportion * length)
        return this.skip(source, count)
    }
    
    static skipSame(source, comparer := (key, other) => key = other)
    {
        iter := Enumerable.clone(source)
        if !iter(&first)
            return false
        fn(&value)
        {
            skipFlag := true
            if !skipFlag
            {
                if !iter(&element)
                    return false
                value := element
                return true
            }
            while skipFlag
            {
                if !iter(&element)
                    return false
                if comparer(first, element)
                    continue
                else
                {
                    value := element
                    skipFlag := false
                    return true
                }
            }
            return false
        }
        Enumerable.toEnumerator(fn)
        fn.params := [source, comparer]
        return fn
    }
    
    static skipWhile(source, predicate := "")
    {
        index := 0
        iter := Enumerable.clone(source)
        fn(&value)
        {
            skipFlag := true
            if !skipFlag
            {
                index++
                if !iter(&element)
                    return false
                value := element
                return true
            }
            while skipFlag
            {
                index++
                if !iter(&element)
                    return false
                if !predicate
                {
                    if isset(element)
                        continue
                    else
                    {
                        value := unset
                        skipFlag := false
                        return true
                    }
                }
                try
                {
                    if predicate(element, index)
                        continue
                    else
                    {
                        value := element
                        skipFlag := false
                        return true
                    }
                }
                catch
                {
                    if predicate(element)
                        continue
                    else
                    {
                        value := element
                        skipFlag := false
                        return true
                    }
                }
            }
            return false
        }
        Enumerable.toEnumerator(fn)
        fn.params := [source, predicate]
        return fn
    }
    
    static slice(source, start := 1, end := "inf")
    {
        index := start
        iter := this.skip(source, start - 1)
        fn(&value)
        {
            if (end != "inf" && index++ > end) || !iter(&element)
                return false
            value := element
            return true
        }
        Enumerable.toEnumerator(fn)
        fn.params := [source, start, end]
        return fn
    }
    
    static some(source, callback, thisArg*)
    {
        try
            return this.any(source, (element, index) => callback.bind(thisArg*)(element, index))
        catch
            return this.any(source, (element, index) => callback.bind(thisArg*)(element))
    }
    
    static split(source, splitPredicate)
    {
        index := 1
        iter := Enumerable.clone(source)
        fn(&_iter)
        {
            if isset(splitflag) && !splitflag
                return false
            splitflag := false
            if !iter(&element)
                return false
            try
            {
                if splitPredicate(element, index++)
                    array_enum := [element]
                else
                {
                    _iter := [].__enum()
                    return true
                }
                while iter(&element)
                {
                    if !splitPredicate(element, index++)
                    {
                        splitflag := true
                        break
                    }
                    array_enum.push(element)
                }
            }
            catch
            {
                if splitPredicate(element)
                    array_enum := [element]
                else
                {
                    _iter := [].__enum()
                    return true
                }
                while iter(&element)
                {
                    if !splitPredicate(element)
                    {
                        splitflag := true
                        break
                    }
                    array_enum.push(element)
                }
            }
            _iter := array_enum.__enum()
            return true
        }
        Enumerable.toEnumerator(fn)
        fn.params := [source, splitPredicate]
        return fn
    }
    
    static sum(source, selector := "")
    {
        sum := 0
        index := 1
        if !selector
        {
            iter := Enumerable.clone(source)
            for element in iter
            {
                sum += element
                if string(sum) = "inf" || string(sum) = "nan"
                    return sum
            }
            return sum
        }
        try
        {
            iter := Enumerable.clone(source)
            for element in iter
            {
                sum += selector(element, index++)
                if string(sum) = "inf" || string(sum) = "nan"
                    return sum
            }
        }
        catch
        {
            iter := Enumerable.clone(source)
            for element in iter
            {
                sum += selector(element)
                if string(sum) = "inf" || string(sum) = "nan"
                    return sum
            }
        }
        return sum
    }
    
    static symmetric(source, other, comparer := (key, other) => key = other)
    {
        temp := []
        others := this.intersect(source, other, comparer)
        iter := Enumerable.clone(source)
        fn(&value)
        {
            if !iter(&element)
                return false
            key := element
            for other in Enumerable.clone(others)
            {
                if comparer(key, other)
                    return fn(&value)
            }
            for other in temp
            {
                if comparer(key, other)
                    return fn(&value)
            }
            value := key
            temp.push(key)
            return true
        }
        Enumerable.toEnumerator(fn)
        fn.params := [source, other, comparer]
        return fn
    }
    
    static take(source, count)
    {
        index := 1
        if count <= 0
            return [].__enum()
        iter := Enumerable.clone(source)
        fn(&value)
        {
            if index > count || !iter(&element)
                return false
            index++
            value := element
            return true
        }
        Enumerable.toEnumerator(fn)
        fn.params := [source, count]
        return fn
    }
    
    static takeProportion(source, proportion)
    {
        length := this.length(source)
        count := floor(proportion * length)
        return this.take(source, count)
    }
    
    static takeSame(source, comparer := (key, other) => key = other)
    {
        iter := Enumerable.clone(source)
        if !iter(&first)
            return false
        firstFlag := true
        fn(&value)
        {
            if firstFlag
            {
                firstFlag := false
                value := first
                return true
            }
            if !iter(&element) || !comparer(first, element)
                return false
            value := element
            return true
        }
        Enumerable.toEnumerator(fn)
        fn.params := [source, comparer]
        return fn
    }
    
    static takeWhile(source, predicate := "")
    {
        index := 1
        iter := Enumerable.clone(source)
        fn(&value)
        {
            if !iter(&element)
                return false
            if !predicate
            {
                if isset(element)
                {
                    value := element
                    return true
                }
                else
                    return false
            }
            try
            {
                if !predicate(element, index++)
                    return false
            }
            catch
            {
                if !predicate(element)
                    return false
            }
            value := element
            return true
        }
        Enumerable.toEnumerator(fn)
        fn.params := [source, predicate]
        return fn
    }
    
    static toArray(source)
    {
        return [Enumerable.clone(source)*]
    }
    
    static toMap(source, keySelector := (key) => key, valueSelector := (value) => value, comparer := (key, other) => key = other)
    {
        enum_map := map()
        iter := Enumerable.clone(source)
        for element in iter
        {
            key := keySelector(element)
            truekey := this.firstOrDefault(this.where(enum_map.__enum(), comparer.bind(key)), "")
            if truekey = ""
                enum_map[key] := valueSelector(element)
            else
                enum_map[truekey] := valueSelector(element)
        }
        return enum_map
    }
    
    static toObject(source, keySelector := (key) => key, valueSelector := (value) => value, comparer := (key, other) => key = other)
    {
        enum_object := {}
        iter := Enumerable.clone(source)
        for element in iter
        {
            key := keySelector(element)
            truekey := this.firstOrDefault(this.where(enum_object.ownprops(), comparer.bind(key)), "")
            if truekey = ""
                enum_object.%key% := valueSelector(element)
            else
                enum_object.%truekey% := valueSelector(element)
        }
        return enum_object
    }
    
    static union(source, other, comparer := (key, other) => key = other)
    {
        temp := []
        iter := Enumerable.clone(source)
        other_iter := Enumerable.clone(other)
        iterFlag := true
        fn(&value)
        {
            if iterFlag && !iter(&element)
                iterFlag := false
            if !iterFlag && !other_iter(&element)
                return false
            key := element
            for other in temp
            {
                if comparer(key, other)
                    return fn(&value)
            }
            value := element
            return true
        }
        Enumerable.toEnumerator(fn)
        fn.params := [source, other, comparer]
        return fn
    }
    
    static where(source, predicate := "")
    {
        index := 1
        iter := Enumerable.clone(source)
        fn(&value)
        {
            if !iter(&element)
                return false
            if !predicate
            {
                if !isset(element)
                    return fn(&value)
                value := element
                return true
            }
            try
            {
                if !predicate(element, index++)
                    return fn(&value)
            }
            catch
            {
                if !predicate(element)
                    return fn(&value)
            }
            value := element
            return true
        }
        Enumerable.toEnumerator(fn)
        fn.params := [source, predicate]
        return fn
    }
    
    static wipe(source, predicate := "", count := 0)
    {
        index := 0
        if !count
            count := this.length(source)
        iter := Enumerable.clone(source)
        fn(&value)
        {
            if !iter(&element)
                return false
            if !predicate
            {
                if isset(element)
                {
                    count--
                    return fn(&value)
                }
                value := unset
                return true
            }
            try
            {
                if predicate(element, index++)
                {
                    count--
                    return fn(&value)
                }
                value := element
                return true
            }
            catch
            {
                if predicate(element)
                {
                    count--
                    return fn(&value)
                }
                value := element
                return true
            }
        }
        Enumerable.toEnumerator(fn)
        fn.params := [source, predicate, count]
        return fn
    }
    
    static zip(source, other, resultSelector := (result, other) => [result, other].__enum())
    {
        iter := Enumerable.clone(source)
        other_iter := Enumerable.clone(other)
        fn(&_iter)
        {
            if !iter(&element) || !other_iter(&_element)
                return false
            _iter := resultSelector(element, _element)
            return true
        }
        Enumerable.toEnumerator(fn)
        fn.params := [source, other, resultSelector]
        return fn
    }
}
Last edited by Mono919 on 22 Mar 2023, 07:29, edited 10 times in total.

iseahound
Posts: 1444
Joined: 13 Aug 2016, 21:04
Contact:

Re: [2.0.2]AHK_Linq(Under development)--Deep use of Enumerator

Post by iseahound » 19 Mar 2023, 10:50

Not really sure how to get this library working. For your each function, I get an error. I'm trying to do IEnumerable.each(a, (x) => MsgBox(x)) for side effects. Not sure if your each function supports side effects!

User avatar
Mono919
Posts: 71
Joined: 05 May 2022, 02:36

Re: [2.0.2]AHK_Linq(Under development)--Deep use of Enumerator

Post by Mono919 » 19 Mar 2023, 11:11

iseahound wrote:
19 Mar 2023, 10:50
Not really sure how to get this library working. For your each function, I get an error. I'm trying to do IEnumerable.each(a, (x) => MsgBox(x)) for side effects. Not sure if your each function supports side effects!
I use this is correct

Code: Select all

a := [1, 2, 3].__enum()
for i in IEnumerable.each(a, (x) => MsgBox(x))
continue
this way is ok too.

Code: Select all

a := [1, 2, 3]
b := Enumerable.asEnumerable(a)
c := IEnumerable.each(b, (x) => MsgBox(x))
for i in c
continue

User avatar
Mono919
Posts: 71
Joined: 05 May 2022, 02:36

Re: [2.0.2]AHK_Linq(Under development)--Deep use of Enumerator

Post by Mono919 » 20 Mar 2023, 08:46

This library can be used now, I will give more examples later.

User avatar
Mono919
Posts: 71
Joined: 05 May 2022, 02:36

Re: [2.0.2]AHK_Linq(Under development)--Deep use of Enumerator

Post by Mono919 » 21 Mar 2023, 10:10

update: 2023.03.21: Support 84 methods and 2 props for Enumerator. Usage is coming soon.

Post Reply

Return to “Scripts and Functions (v2)”