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))
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))
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))
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))
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
}
}