Plato on Github
Report Home
classlib/Collections/Collection.js
Maintainability
120.79
Lines of code
1048
Difficulty
101.96
Estimated Errors
10.61
Function weight
By Complexity
By SLOC
SCScript.install(function(sc) { "use strict"; require("../Core/Object"); var $ = sc.lang.$; var $nil = $.nil; var $true = $.true; var $false = $.false; var $int0 = $.int0; var $int1 = $.int1; var SCArray = $("Array"); sc.lang.klass.refine("Collection", function(builder) { builder.addClassMethod("newFrom", { args: "aCollection" }, function($aCollection) { var $newCollection; $newCollection = this.new($aCollection.size()); $aCollection.do($.Func(function($item) { return $newCollection.add($item); })); return $newCollection; }); builder.addClassMethod("with", { args: "*args" }, function($$args) { var $newColl; $newColl = this.new($$args.size()); $newColl.addAll($$args); return $newColl; }); builder.addClassMethod("fill", { args: "size; function" }, function($size, $function) { var $obj; var size, i; if ($size.isSequenceableCollection().__bool__()) { return this.fillND($size, $function); } $obj = this.new($size); size = $size.__int__(); for (i = 0; i < size; ++i) { $obj.add($function.value($.Integer(i))); } return $obj; }); builder.addClassMethod("fill2D", { args: "rows; cols; function" }, function($rows, $cols, $function) { var $this = this, $obj, $obj2, $row, $col; var rows, cols, i, j; $obj = this.new($rows); rows = $rows.__int__(); cols = $cols.__int__(); for (i = 0; i < rows; ++i) { $row = $.Integer(i); $obj2 = $this.new($cols); for (j = 0; j < cols; ++j) { $col = $.Integer(j); $obj2 = $obj2.add($function.value($row, $col)); } $obj = $obj.add($obj2); } return $obj; }); builder.addClassMethod("fill3D", { args: "planes; rows; cols; function" }, function($planes, $rows, $cols, $function) { var $this = this, $obj, $obj2, $obj3, $plane, $row, $col; var planes, rows, cols, i, j, k; $obj = this.new($planes); planes = $planes.__int__(); rows = $rows .__int__(); cols = $cols .__int__(); for (i = 0; i < planes; ++i) { $plane = $.Integer(i); $obj2 = $this.new($rows); for (j = 0; j < rows; ++j) { $row = $.Integer(j); $obj3 = $this.new($cols); for (k = 0; k < cols; ++k) { $col = $.Integer(k); $obj3 = $obj3.add($function.value($plane, $row, $col)); } $obj2 = $obj2.add($obj3); } $obj = $obj.add($obj2); } return $obj; }); var fillND = function($this, $dimensions, $function, $args) { var $n, $obj, $argIndex; $n = $dimensions.$("first"); $obj = $this.new($n); $argIndex = $args.size(); $args = $args ["++"] ($int0); if ($dimensions.size().__int__() <= 1) { $n.do($.Func(function($i) { return $obj.add($function.valueArray($args.put($argIndex, $i))); })); } else { $dimensions = $dimensions.$("drop", [ $int1 ]); $n.do($.Func(function($i) { $obj = $obj.add(fillND($this, $dimensions, $function, $args.put($argIndex, $i))); return $obj; })); } return $obj; }; builder.addClassMethod("fillND", { args: "dimensions; function" }, function($dimensions, $function) { return fillND(this, $dimensions, $function, $.Array([])); }); builder.addMethod("@", function($index) { return this.at($index); }); builder.addMethod("==", function($aCollection) { var $res = null; if ($aCollection.class() !== this.class()) { return $false; } if (this.size() !== $aCollection.size()) { return $false; } this.do($.Func(function($item) { if (!$aCollection.$("includes", [ $item ]).__bool__()) { $res = $false; this.break(); } return $nil; })); return $res || $true; }); // TODO: implements hash builder.addMethod("species", function() { return SCArray; }); builder.subclassResponsibility("do"); // TODO: implements iter builder.addMethod("size", function() { var tally = 0; this.do($.Func(function() { tally += 1; return $nil; })); return $.Integer(tally); }); builder.addMethod("flatSize", function() { return this.sum($.Func(function($_) { return $_.$("flatSize"); })); }); builder.addMethod("isEmpty", function() { return $.Boolean(this.size().__int__() === 0); }); builder.addMethod("notEmpty", function() { return $.Boolean(this.size().__int__() !== 0); }); builder.addMethod("asCollection"); builder.addMethod("isCollection", sc.TRUE); builder.subclassResponsibility("add"); builder.addMethod("addAll", { args: "aCollection" }, function($aCollection) { var $this = this; $aCollection.asCollection().do($.Func(function($item) { return $this.add($item); })); return this; }); builder.subclassResponsibility("remove"); builder.addMethod("removeAll", { args: "list" }, function($list) { var $this = this; $list.do($.Func(function($item) { return $this.remove($item); })); return this; }); builder.addMethod("removeEvery", { args: "list" }, function($list) { this.removeAllSuchThat($.Func(function($_) { return $list.$("includes", [ $_ ]); })); return this; }); builder.addMethod("removeAllSuchThat", function($function) { var $this = this, $removedItems, $copy; $removedItems = this.class().new(); $copy = this.copy(); $copy.do($.Func(function($item) { if ($function.value($item).__bool__()) { $this.remove($item); $removedItems = $removedItems.add($item); } return $nil; })); return $removedItems; }); builder.addMethod("atAll", { args: "keys" }, function($keys) { var $this = this; return $keys.$("collect", [ $.Func(function($index) { return $this.at($index); }) ]); }); builder.addMethod("putEach", { args: "keys; values" }, function($keys, $values) { var keys, values, i, imax; $keys = $keys.asArray(); $values = $values.asArray(); keys = $keys._; values = $values._; for (i = 0, imax = keys.length; i < imax; ++i) { this.put(keys[i], values[i % values.length]); } return this; }); builder.addMethod("includes", { args: "item1" }, function($item1) { var $res = null; this.do($.Func(function($item2) { if ($item1 === $item2) { $res = $true; this.break(); } return $nil; })); return $res || $false; }); builder.addMethod("includesEqual", { args: "item1" }, function($item1) { var $res = null; this.do($.Func(function($item2) { if ($item1 ["=="] ($item2).__bool__()) { $res = $true; this.break(); } return $nil; })); return $res || $false; }); builder.addMethod("includesAny", { args: "aCollection" }, function($aCollection) { var $this = this, $res = null; $aCollection.do($.Func(function($item) { if ($this.includes($item).__bool__()) { $res = $true; this.break(); } return $nil; })); return $res || $false; }); builder.addMethod("includesAll", { args: "aCollection" }, function($aCollection) { var $this = this, $res = null; $aCollection.do($.Func(function($item) { if (!$this.includes($item).__bool__()) { $res = $false; this.break(); } return $nil; })); return $res || $true; }); builder.addMethod("matchItem", { args: "item" }, function($item) { return this.includes($item); }); builder.addMethod("collect", function($function) { return this.collectAs($function, this.species()); }); builder.addMethod("select", function($function) { return this.selectAs($function, this.species()); }); builder.addMethod("reject", function($function) { return this.rejectAs($function, this.species()); }); builder.addMethod("collectAs", { args: "function; class" }, function($function, $class) { var $res; $res = $class.new(this.size()); this.do($.Func(function($elem, $i) { return $res.add($function.value($elem, $i)); })); return $res; }); builder.addMethod("selectAs", { args: "function; class" }, function($function, $class) { var $res; $res = $class.new(this.size()); this.do($.Func(function($elem, $i) { if ($function.value($elem, $i).__bool__()) { $res = $res.add($elem); } return $nil; })); return $res; }); builder.addMethod("rejectAs", { args: "function; class" }, function($function, $class) { var $res; $res = $class.new(this.size()); this.do($.Func(function($elem, $i) { if (!$function.value($elem, $i).__bool__()) { $res = $res.add($elem); } return $nil; })); return $res; }); builder.addMethod("detect", function($function) { var $res = null; this.do($.Func(function($elem, $i) { if ($function.value($elem, $i).__bool__()) { $res = $elem; this.break(); } return $nil; })); return $res || $nil; }); builder.addMethod("detectIndex", function($function) { var $res = null; this.do($.Func(function($elem, $i) { if ($function.value($elem, $i).__bool__()) { $res = $i; this.break(); } return $nil; })); return $res || $nil; }); builder.addMethod("doMsg", function() { var args = arguments; this.do($.Func(function($item) { return $item.perform.apply($item, args); })); return this; }); builder.addMethod("collectMsg", function() { var args = arguments; return this.collect($.Func(function($item) { return $item.perform.apply($item, args); })); }); builder.addMethod("selectMsg", function() { var args = arguments; return this.select($.Func(function($item) { return $item.perform.apply($item, args); })); }); builder.addMethod("rejectMsg", function() { var args = arguments; return this.reject($.Func(function($item) { return $item.perform.apply($item, args); })); }); builder.addMethod("detectMsg", { args: "selector; *args" }, function($selector, $$args) { return this.detect($.Func(function($item) { return $item.performList($selector, $$args); })); }); builder.addMethod("detectIndexMsg", { args: "selector; *args" }, function($selector, $$args) { return this.detectIndex($.Func(function($item) { return $item.performList($selector, $$args); })); }); builder.addMethod("lastForWhich", function($function) { var $res = null; this.do($.Func(function($elem, $i) { if ($function.value($elem, $i).__bool__()) { $res = $elem; } else { this.break(); } return $nil; })); return $res || $nil; }); builder.addMethod("lastIndexForWhich", function($function) { var $res = null; this.do($.Func(function($elem, $i) { if ($function.value($elem, $i).__bool__()) { $res = $i; } else { this.break(); } return $nil; })); return $res || $nil; }); builder.addMethod("inject", { args: "thisValue; function" }, function($thisValue, $function) { var $nextValue; $nextValue = $thisValue; this.do($.Func(function($item, $i) { $nextValue = $function.value($nextValue, $item, $i); return $nextValue; })); return $nextValue; }); builder.addMethod("injectr", { args: "thisValue; function" }, function($thisValue, $function) { var $this = this, size, $nextValue; size = this.size().__int__(); $nextValue = $thisValue; this.do($.Func(function($item, $i) { $item = $this.at($.Integer(--size)); $nextValue = $function.value($nextValue, $item, $i); return $nextValue; })); return $nextValue; }); builder.addMethod("count", function($function) { var sum = 0; this.do($.Func(function($elem, $i) { if ($function.value($elem, $i).__bool__()) { sum++; } return $nil; })); return $.Integer(sum); }); builder.addMethod("occurrencesOf", { args: "obj" }, function($obj) { var sum = 0; this.do($.Func(function($elem) { if ($elem ["=="] ($obj).__bool__()) { sum++; } return $nil; })); return $.Integer(sum); }); builder.addMethod("any", function($function) { var $res = null; this.do($.Func(function($elem, $i) { if ($function.value($elem, $i).__bool__()) { $res = $true; this.break(); } return $nil; })); return $res || $false; }); builder.addMethod("every", function($function) { var $res = null; this.do($.Func(function($elem, $i) { if (!$function.value($elem, $i).__bool__()) { $res = $false; this.break(); } return $nil; })); return $res || $true; }); builder.addMethod("sum", { args: "function" }, function($function) { var $sum; $sum = $int0; if ($function === $nil) { this.do($.Func(function($elem) { $sum = $sum ["+"] ($elem); return $sum; })); } else { this.do($.Func(function($elem, $i) { $sum = $sum ["+"] ($function.value($elem, $i)); return $sum; })); } return $sum; }); builder.addMethod("mean", function($function) { return this.sum($function) ["/"] (this.size()); }); builder.addMethod("product", { args: "function" }, function($function) { var $product; $product = $int1; if ($function === $nil) { this.do($.Func(function($elem) { $product = $product ["*"] ($elem); return $product; })); } else { this.do($.Func(function($elem, $i) { $product = $product ["*"] ($function.value($elem, $i)); return $product; })); } return $product; }); builder.addMethod("sumabs", function() { var $sum; $sum = $int0; this.do($.Func(function($elem) { if ($elem.isSequenceableCollection().__bool__()) { $elem = $elem.at($int0); } $sum = $sum ["+"] ($elem.abs()); return $sum; })); return $sum; }); builder.addMethod("maxItem", { args: "function" }, function($function) { var $maxValue, $maxElement; $maxValue = $nil; $maxElement = $nil; if ($function === $nil) { this.do($.Func(function($elem) { if ($maxElement === $nil) { $maxElement = $elem; } else if ($elem > $maxElement) { $maxElement = $elem; } return $nil; })); } else { this.do($.Func(function($elem, $i) { var $val; if ($maxValue === $nil) { $maxValue = $function.value($elem, $i); $maxElement = $elem; } else { $val = $function.value($elem, $i); if ($val > $maxValue) { $maxValue = $val; $maxElement = $elem; } } return $nil; })); } return $maxElement; }); builder.addMethod("minItem", { args: "function" }, function($function) { var $minValue, $minElement; $minValue = $nil; $minElement = $nil; if ($function === $nil) { this.do($.Func(function($elem) { if ($minElement === $nil) { $minElement = $elem; } else if ($elem < $minElement) { $minElement = $elem; } return $nil; })); } else { this.do($.Func(function($elem, $i) { var $val; if ($minValue === $nil) { $minValue = $function.value($elem, $i); $minElement = $elem; } else { $val = $function.value($elem, $i); if ($val < $minValue) { $minValue = $val; $minElement = $elem; } } return $nil; })); } return $minElement; }); builder.addMethod("maxIndex", { args: "function" }, function($function) { var $maxValue, $maxIndex; $maxValue = $nil; $maxIndex = $nil; if ($function === $nil) { this.do($.Func(function($elem, $index) { if ($maxValue === $nil) { $maxValue = $elem; $maxIndex = $index; } else if ($elem > $maxValue) { $maxValue = $elem; $maxIndex = $index; } return $nil; })); } else { this.do($.Func(function($elem, $i) { var $val; if ($maxValue === $nil) { $maxValue = $function.value($elem, $i); $maxIndex = $i; } else { $val = $function.value($elem, $i); if ($val > $maxValue) { $maxValue = $val; $maxIndex = $i; } } return $nil; })); } return $maxIndex; }); builder.addMethod("minIndex", { args: "function" }, function($function) { var $maxValue, $minIndex; $maxValue = $nil; $minIndex = $nil; if ($function === $nil) { this.do($.Func(function($elem, $index) { if ($maxValue === $nil) { $maxValue = $elem; $minIndex = $index; } else if ($elem < $maxValue) { $maxValue = $elem; $minIndex = $index; } return $nil; })); } else { this.do($.Func(function($elem, $i) { var $val; if ($maxValue === $nil) { $maxValue = $function.value($elem, $i); $minIndex = $i; } else { $val = $function.value($elem, $i); if ($val < $maxValue) { $maxValue = $val; $minIndex = $i; } } return $nil; })); } return $minIndex; }); builder.addMethod("maxValue", { args: "function" }, function($function) { var $maxValue, $maxElement; $maxValue = $nil; $maxElement = $nil; this.do($.Func(function($elem, $i) { var $val; if ($maxValue === $nil) { $maxValue = $function.value($elem, $i); $maxElement = $elem; } else { $val = $function.value($elem, $i); if ($val > $maxValue) { $maxValue = $val; $maxElement = $elem; } } return $nil; })); return $maxValue; }); builder.addMethod("minValue", { args: "function" }, function($function) { var $minValue, $minElement; $minValue = $nil; $minElement = $nil; this.do($.Func(function($elem, $i) { var $val; if ($minValue === $nil) { $minValue = $function.value($elem, $i); $minElement = $elem; } else { $val = $function.value($elem, $i); if ($val < $minValue) { $minValue = $val; $minElement = $elem; } } return $nil; })); return $minValue; }); builder.addMethod("maxSizeAtDepth", { args: "rank" }, function($rank) { var rank, maxsize = 0; rank = $rank.__num__(); if (rank === 0) { return this.size(); } this.do($.Func(function($sublist) { var sz; if ($sublist.isCollection().__bool__()) { sz = $sublist.maxSizeAtDepth($.Integer(rank - 1)); } else { sz = 1; } if (sz > maxsize) { maxsize = sz; } return $nil; })); return $.Integer(maxsize); }); builder.addMethod("maxDepth", { args: "max=1" }, function($max) { var $res; $res = $max; this.do($.Func(function($elem) { if ($elem.isCollection().__bool__()) { $res = $res.max($elem.maxDepth($max.__inc__())); } return $nil; })); return $res; }); builder.addMethod("deepCollect", { args: "depth=1; function; index=0; rank=0" }, function($depth, $function, $index, $rank) { if ($depth === $nil) { $rank = $rank.__inc__(); return this.collect($.Func(function($item, $i) { return $item.deepCollect($depth, $function, $i, $rank); })); } if ($depth.__num__() <= 0) { return $function.value(this, $index, $rank); } $depth = $depth.__dec__(); $rank = $rank.__inc__(); return this.collect($.Func(function($item, $i) { return $item.deepCollect($depth, $function, $i, $rank); })); }); builder.addMethod("deepDo", { args: "depth=1; function; index=0; rank=0" }, function($depth, $function, $index, $rank) { if ($depth === $nil) { $rank = $rank.__inc__(); return this.do($.Func(function($item, $i) { return $item.deepDo($depth, $function, $i, $rank); })); } if ($depth.__num__() <= 0) { $function.value(this, $index, $rank); return this; } $depth = $depth.__dec__(); $rank = $rank.__inc__(); return this.do($.Func(function($item, $i) { return $item.deepDo($depth, $function, $i, $rank); })); }); builder.addMethod("invert", { args: "axis" }, function($axis) { var $index; if (this.isEmpty().__bool__()) { return this.species().new(); } if ($axis !== $nil) { $index = $axis.$("*", [ $.Integer(2) ]); } else { $index = this.minItem().$("+", [ this.maxItem() ]); } return $index ["-"] (this); }); builder.addMethod("sect", { args: "that" }, function($that) { var $result; $result = this.species().new(); this.do($.Func(function($item) { if ($that.$("includes", [ $item ]).__bool__()) { $result = $result.add($item); } return $nil; })); return $result; }); builder.addMethod("union", { args: "that" }, function($that) { var $result; $result = this.copy(); $that.do($.Func(function($item) { if (!$result.includes($item).__bool__()) { $result = $result.add($item); } return $nil; })); return $result; }); builder.addMethod("difference", { args: "that" }, function($that) { return this.copy().removeAll($that); }); builder.addMethod("symmetricDifference", { args: "that" }, function($that) { var $this = this, $result; $result = this.species().new(); $this.do($.Func(function($item) { if (!$that.includes($item).__bool__()) { $result = $result.add($item); } return $nil; })); $that.do($.Func(function($item) { if (!$this.includes($item).__bool__()) { $result = $result.add($item); } return $nil; })); return $result; }); builder.addMethod("isSubsetOf", { args: "that" }, function($that) { return $that.$("includesAll", [ this ]); }); builder.addMethod("asArray", function() { return SCArray.new(this.size()).addAll(this); }); builder.addMethod("asBag", function() { return $("Bag").new(this.size()).addAll(this); }); builder.addMethod("asList", function() { return $("List").new(this.size()).addAll(this); }); builder.addMethod("asSet", function() { return $("Set").new(this.size()).addAll(this); }); builder.addMethod("asSortedList", function($function) { return $("SortedList").new(this.size(), $function).addAll(this); }); // TODO: implements powerset // TODO: implements flopDict // TODO: implements histo // TODO: implements printAll // TODO: implements printcsAll // TODO: implements dumpAll // TODO: implements printOn // TODO: implements storeOn // TODO: implements storeItemsOn // TODO: implements printItemsOn // TODO: implements writeDef // TODO: implements writeInputSpec // TODO: implements case // TODO: implements makeEnvirValPairs builder.addMethod("asString", function() { var items = []; this.do($.Func(function($elem) { items.push($elem.__str__()); return $nil; })); return $.String( this.__className + "[ " + items.join(", ") + " ]" ); }); }); });