- ۳۳۱ بازديد
- ۱۰ فروردین ۱۳۹۶
- آموزش برنامه نویسی, آموزش سی شارپ

با آموزش LINQ برای جاوا اسکریپت با شما هستیم،این مقاله قابلیت های اولیه LINQ اعمال شده روی آرایه های جاوا اسکریپت را مرور می کند.LINQ کامپوننتی از Microsoft .NET Framework است که با اضافه کردن عبارات کوئری زبان را توسعه می دهد، که به دستورات SQL وابسته است، و می تواند به راحتی داده ها را از آرایه ها گرفته و پردازش نماید. API تعبیه شده جاوا اسکریپت از ویرایش ECMAScript 5th با مجموعه بسیار محدودی از متدهای تکرار: forEach، some، filter، map، reduce و reduceRight می آید.
این متدها قابل پشتیبانی در همه مرورگرها نیستند، متفاوت از LINQ API بوده و بسیاری از قابلیت هایی که با LINQ می آید را پوشش نمی دهند. این مقاله پیاده سازی بیش از ۳۰ متد Enumerable از .NET 4.0 در جاوا اسکریپت شامل Aggregations، Iterations، Predicators و Selectors را برای افزودن قدرت و انعطاف پذیری کوئری های سبک LINQ به کد جاوا اسکریپت قدیمی را پوشش می دهد.
پیش زمینه
جاوا اسکریپت به طور ذاتی از وراثت کلاس پشتیبانی نمی کند و از طریق prototype به طور نامرتبی آن را پشتیبانی می کند. امکان شبیه سازی بسیاری از ویژگی های مبتنی بر کلاس در جاوا اسکریپت وجود دارد. Prototypeها ویژگی های رایج شی گرایی را برای زبان برنامه نویسی شی گرا فراهم می نماید. به این معنی که برای اضافه کردن قابلیت های بیشتر به API تعبیه شده، می توان prototype کلاس را توسعه داد.
همه آرایه ها در جاوا اسکریپت از شی Array ارث بری می کنند و متدها و property ها را از Array.prototype به ارث می برند. تغییرات روی شی Array prototype به همه آرایه ها منتشر می شود مگر اینکه propertyها و متدهای مربوط به این تغییرات در این زنجیره prototype، override شده باشند.
برای اضافه کردن قابلیت LINQ به جاوا اسکریپت، تمام کاری که ما باید انجام دهیم اضافه کردن این متدها به شی Array.prototype است.
برای مثال، API جاوا اسکریپت متد union ندارد، اگرچه متد concat را تقریبا با همان قابلیت دارد. با قرار دادن Array.prototype.union در متد تعبیه شده concat، همه آرایه ها جاوا اسکریپت می توانند متد union هم داشته باشند.
(متد صحیح union از المنت های گسسته از اجتماع دو دنباله استفاده می کند.)
Array.prototype.union = Array.prototype.concat;
قبل از شروع
بیشتر متدهای LINQ، به توابع EqualityComparer، SortComparer، Predicate یا Selector برای اعمال هر المنتی درون یک آرایه نیاز دارند. در .NET این کار با ارسال Delegate به متد انجام می شود. به عنوان مثال این مدلی است که متد Select باید در C# ظاهر شود.
var someArray = new int[] { 1, 2, 3, 4 }; var otherArray = someArray.Select(t => t * 2);
در مثال بالا t => t *2 یک Lambda expression است که برای ضرب هریک از المنت های آرایه در ۲ به عنوان یک تابع بی نام (delegate) رفتار می کند. اگرچه، از آن جایی که جاوا اسکریپت با عبارات Lambda نمی آید، توابع بی نام در جاوا اسکریپت با استفاده از function(){ … } تعریف می شوند.
این مدلی است که متد select در جاوا اسکریپت ظاهر می شود:
var someArray = [1, 2, 3, 4]; var otherArray = someArray.select(function (t) { return t * 2 });
اینجا توابع پیش فرض EqualityComparer، SortComparer، Predicate یا Selector را داریم:
function DefaultEqualityComparer(a, b) { return a === b || a.valueOf() === b.valueOf(); }; function DefaultSortComparer(a, b) { if (a === b) return 0; if (a == null) return -1; if (b == null) return 1; if (typeof a == "string") return a.toString().localeCompare(b.toString()); return a.valueOf() - b.valueOf(); }; function DefaultPredicate() { return true; }; function DefaultSelector(t) { return t; };
LINQ Selector های جاوا اسکریپت
Select
هر یک از المنت های یک دنباله را به شکل جدیدی project می کند.
Array.prototype.select = Array.prototype.map || function (selector, context) { context = context || window; var arr = []; var l = this.length; for (var i = 0; i < l; i++) arr.push(selector.call(context, this[i], i, this)); return arr; };
مثال:
var arr = [1, 2, 3, 4, 5]; var doubled = arr.select(function(t){ return t * 2 }); // [2, 4, 6, 8, 10]
SelectMany
هر یک از المنت های یک دنباله را به یک آرایه project کرده و دنباله های نتیجه را در آخر به شکل یک آرایه درمی آورد:
Array.prototype.selectMany = function (selector, resSelector) { resSelector = resSelector || function (i, res) { return res; }; return this.aggregate(function (a, b, i) { return a.concat(selector(b, i).select(function (res) { return resSelector(b, res) })); }, []); };
مثال:
var arr = [{Name:"A", Values:[1, 2, 3, 4]}, {Name:"B", Values:[5, 6, 7, 8]}]; var res1 = arr.selectMany(function(t){ return t.Values }); // using default result selector var res2 = arr.selectMany(function(t){ return t.Values }, function(t, u){ return {Name:t.Name, Val:u}}); // using custom result selector
Take
تعداد مشخصی از المنت های پیوسته را از آغاز یک دنباله برمی گرداند.
Array.prototype.take = function (c) { return this.slice(0, c); };
مثال:
var arr = [1, 2, 3, 4, 5]; var res = arr.take(2); // [1, 2]
Skip
از روی تعداد مشخصی از المنت های دنباله گذشته و آن ها را نادیده گرفته و المنت های باقیمانده را برمی گرداند.
Array.prototype.skip = function (c) { return this.slice(c); };
مثال:
var arr = [1, 2, 3, 4, 5]; var res = arr.skip(2); // [3, 4, 5]
First
اولین المنت دنباله را برمی گرداند:
Array.prototype.first = function (predicate, def) { var l = this.length; if (!predicate) return l ? this[0] : def == null ? null : def; for (var i = 0; i < l; i++) if (predicate(this[i], i, this)) return this[i]; return def == null ? null : def; };
مثال:
var arr = [1, 2, 3, 4, 5]; var t1 = arr.first(); // 1 var t2 = arr.first(function(t){ return t > 2 }); // using comparer: 3 var t3 = arr.first(function(t){ return t > 10 }, 10); // using comparer and default value: 10
Last
آخرین المنت دنباله را برمی گرداند.
Array.prototype.last = function (predicate, def) { var l = this.length; if (!predicate) return l ? this[l - 1] : def == null ? null : def; while (l-- > 0) if (predicate(this[l], l, this)) return this[l]; return def == null ? null : def; };
مثال:
var arr = [1, 2, 3, 4, 5]; var t1 = arr.last(); // 5 var t2 = arr.last(function(t){ return t > 2 }); // using comparer: 5 var t3 = arr.last(function(t){ return t > 10 }, 10); // using comparer and default value: 10
Union
اجتماع دو دنباله را با استفاده از equality comparer پیش فرض تولید می کند.
Array.prototype.union = function (arr) { return this.concat(arr).distinct(); };
مثال:
var arr1 = [1, 2, 3, 4, 5]; var arr2 = [5, 6, 7, 8, 9]; var res = arr1.union(arr2); // [1, 2, 3, 4, 5, 6, 7, 8, 9]
Intersect
اشتراک دو دنباله را تولید می نماید.
Array.prototype.intersect = function (arr, comparer) { comparer = comparer || DefaultEqualityComparer; return this.distinct(comparer).where(function (t) { return arr.contains(t, comparer); }); };
مثال:
var arr1 = [1, 2, 3, 4, 5]; var arr2 = [1, 2, 3]; var res = arr1.intersect(arr2); // [1, 2, 3]
Except
تفاضل دو دنباله را محاسبه می نماید.
Array.prototype.except = function (arr, comparer) { if (!(arr instanceof Array)) arr = [arr]; comparer = comparer || DefaultEqualityComparer; var l = this.length; var res = []; for (var i = 0; i < l; i++) { var k = arr.length; var t = false; while (k-- > 0) { if (comparer(this[i], arr[k]) === true) { t = true; break; } } if (!t) res.push(this[i]); } return res; };
مثال:
var arr1 = [1, 2, 3, 4, 5]; var arr2 = [2, 3, 4]; var res = arr1.except(arr2); // [1, 5]
Distinct
المنت های غیرتکراری از یک دنباله را با استفاده از equality comparer پیش فرض جهت مقایسه مقادیر برمی گرداند.
Array.prototype.distinct = function (comparer) { var arr = []; var l = this.length; for (var i = 0; i < l; i++) { if (!arr.contains(this[i], comparer)) arr.push(this[i]); } return arr; };
مثال:
var arr1 = [1, 2, 2, 3, 3, 4, 5, 5]; var res1 = arr.distinct(); // [1, 2, 3, 4, 5] var arr2 = [{Name:"A", Val:1}, {Name:"B", Val:1}]; var res2 = arr2.distinct(function(a, b){ return a.Val == b.Val }); // [{Name:"A", Val:1}] ;
Zip
یک تابع به خصوص را روی المنت های مربوط به هر دو دنباله اعمال می کند که یک دنباله به عنوان نتیجه تولید می کند.
Array.prototype.zip = function (arr, selector) { return this .take(Math.min(this.length, arr.length)) .select(function (t, i) { return selector(t, arr[i]); }); };
مثال:
var arr1 = [1, 2, 3, 4]; var arr2 = ["A", "B", "C", "D"]; var res = arr1.zip(arr2, function(a, b){ return {Num:a, Letter:b} }); // [{Num:1, Letter: "A"},{Num:2, Letter: "B"}, {Num:3, Letter: "C"}, {Num:4, Letter: "D"}]
IndexOf
اندیس اولین جایی که یک مقدار آمده است را در یک آرایه یک بعدی به ما می دهد.
Array.prototype.indexOf = Array.prototype.indexOf || function (o, index) { var l = this.length; for (var i = Math.max(Math.min(index, l), 0) || 0; i < l; i++) if (this[i] === o) return i; return -1; };
مثال:
var arr = [1, 2, 3, 4, 5]; var index = arr.indexOf(2); // 1
LastIndexOf
اندیس آخرین جایی که یک مقدار در یک آرایه یک بعدی آمده است را به ما می دهد.
Array.prototype.lastIndexOf = Array.prototype.lastIndexOf || function (o, index) { var l = Math.max(Math.min(index || this.length, this.length), 0); while (l-- > 0) if (this[l] === o) return l; return -1; };
مثال:
var arr = [1, 2, 3, 4, 5, 3, 4, 5]; var index = arr.lastIndexOf(3); // 5
Remove
یک شی مشخصی از آرایه را در اولین جایی که آمده است، حذف می کند.
Array.prototype.remove = function (item) { var i = this.indexOf(item); if (i != -1) this.splice(i, 1); };
مثال:
var arr = [1, 2, 3, 4, 5]; arr.remove(2); // [1, 3, 4, 5]
RemoveAll
تمام المنت هایی که با شرطی که توسط predicate مشخص شده مطابقت دارند، حذف می کند.
Array.prototype.removeAll = function (predicate) { var item; var i = 0; while (item = this.first(predicate)) { i++; this.remove(item); } return i; };
مثال:
var arr = [1, 2, 3, 4, 5]; arr.removeAll(function(t){ return t % 2 == 0 }); // [1, 3, 5]
OrderBy
المنت های یک دنباله را در جهت صعودی براساس یک کلید مرتب می کند.
Array.prototype.orderBy = function (selector, comparer) { comparer = comparer || DefaultSortComparer; var arr = this.slice(0); var fn = function (a, b) { return comparer(selector(a), selector(b)); }; arr.thenBy = function (selector, comparer) { comparer = comparer || DefaultSortComparer; return arr.orderBy(DefaultSelector, function (a, b) { var res = fn(a, b); return res === 0 ? comparer(selector(a), selector(b)) : res; }); }; arr.thenByDescending = function (selector, comparer) { comparer = comparer || DefaultSortComparer; return arr.orderBy(DefaultSelector, function (a, b) { var res = fn(a, b); return res === 0 ? -comparer(selector(a), selector(b)) : res; }); }; return arr.sort(fn); };
مثال:
var arr = [{Name:"A", Val:1}, {Name:"a", Val:2}, {Name:"B", Val:1}, {Name:"C", Val:2}]; var res1 = arr.orderBy(function(t){ return t.Name }); var res2 = arr.orderBy(function(t){ return t.Name }, function(a, b){ if(a.toUpperCase() > b.toUpperCase()) return 1; if(a.toUpperCase() < b.toUpperCase()) return -1; return 0; });
OrderByDescending
المنت های یک دنباله را در جهت نزولی مرتب می کند.
Array.prototype.orderByDescending = function (selector, comparer) { comparer = comparer || DefaultSortComparer; return this.orderBy(selector, function (a, b) { return -comparer(a, b) }); };
مثال:
var arr = [{Name:"A", Val:1}, {Name:"a", Val:2}, {Name:"B", Val:1}, {Name:"C", Val:2}]; var res = arr.orderByDescending(function(t){ return t.Name });
ThenBy/ThenByDescending
یک مرتب سازی با تاخیر روی المنت های یک دنباله را با استفاده از یک مقایسه گر مشخص در جهت صعودی/نزولی انجام می دهد. ThenBy و ThenByDescending برای توسعه نوع خروجی OrderBy و OrderByDescending تعریف می شوند که نوع این متدها را برمی گردانند. این طراحی ما را قادر می سازد که چندین معیار مرتب سازی را با اعمال هر تعداد از متدهای ThenBy و ThenByDescending مشخص کنیم.
مثال:
var arr = [{Name:"A", Val:1}, {Name:"a", Val:2}, {Name:"B", Val:1}, {Name:"C", Val:2}]; var res1 = arr.orderBy(function(t){ return t.Val }) .thenBy(function(t){ return t.Name }); var res2 = arr.orderBy(function(t){ return t.Val }) .thenByDescending(function(t){ return t.Name }); var res3 = arr.orderByDescending(function(t){ return t.Val }) .thenBy(function(t){ return t.Name });
InnerJoin
المنت های دو دنباله را براساس کلیدهای مطابقت به هم مرتبط می کند.
Array.prototype.innerJoin = function (arr, outer, inner, result, comparer) { comparer = comparer || DefaultEqualityComparer; var res = []; this.forEach(function (t) { arr.where(function (u) { return comparer(outer(t), inner(u)); }) .forEach(function (u) { res.push(result(t, u)); }); }); return res; };
مثال:
var arr1 = [{Name:"A", Val:1}, {Name:"B", Val:2}, {Name:"C", Val:3}]; var arr2 = [{Code:"A"}, {Code:"B"}, {Name:"C", Code:"C"}]; var res1 = arr1.innerJoin(arr2, function (t) { return t.Name }, // arr1 selector function (u) { return u.Code }, // arr2 selector function (t, u) { return { Name: t.Name, Val: t.Val, Code: u.Code } }); // result selector // using custom comparer var res2 = arr1.innerJoin(arr2, function (t) { return t.Name }, // arr1 selector function (u) { return u.Code }, // arr2 selector function (t, u) { return { Name: t.Name, Val: t.Val, Code: u.Code } }, // result selector function (a, b) { return a.toUpperCase() == b.toUpperCase() }); // comparer
GroupJoin
المنت های دو دنباله را براساس شباهت کلیدها و گروه بندی نتایج به هم مرتبط می کند. Equality comparer پیش فرض برای مقایسه کلیدها استفاده می شود.
Array.prototype.groupJoin = function (arr, outer, inner, result, comparer) { comparer = comparer || DefaultEqualityComparer; return this .select(function (t) { var key = outer(t); return { outer: t, inner: arr.where(function (u) { return comparer(key, inner(u)); }), key: key }; }) .select(function (t) { t.inner.key = t.key; return result(t.outer, t.inner); }); };
مثال:
var arr1 = [{Name:"A", Val:1}, {Name:"B", Val:2}, {Name:"C", Val:3}]; var arr2 = [{Code:"A"}, {Code:"A"}, {Code:"B"}, {Code:"B"}, {Code:"C"}]; var res1 = arr1.groupJoin(arr2, function(t){ return t.Name }, // arr1 selector function(u){ return u.Code }, // arr2 selector function(t, u){ return {Item:t, Group:u} }) ; // result selector // using custom comparer var res2 = arr1.groupJoin(arr2, function(t){ return t.Name }, // arr1 selector function(u){ return u.Code }, // arr2 selector function(t, u){ return {Item:t, Group:u} }, // result selector function(a, b){ return a.toUpperCase() == b.toUpperCase() }); // comparer
GroupBy
المنت های یک دنباله را براساس یک تابع انتخاب گر کلید مشخص گروه بندی می نماید.
Array.prototype.groupBy = function (selector, comparer) { var grp = []; var l = this.length; comparer = comparer || DefaultEqualityComparer; selector = selector || DefaultSelector; for (var i = 0; i < l; i++) { var k = selector(this[i]); var g = grp.first(function (u) { return comparer(u.key, k); }); if (!g) { g = []; g.key = k; grp.push(g); } g.push(this[i]); } return grp; };
مثال:
var arr = [{Name:"A", Val:1}, {Name:"B", Val:1}, {Name:"C", Val:2}, {Name:"D", Val:2}]; var res = arr.groupBy(function(t){ return t.Val }); // [[{Name:"A", Val:1}, {Name:"B", Val:1}], [{Name:"C", Val:2}, {Name:"D", Val:2}]] res.forEach(function(t){ console.log("Key: " + t.key, "Length: " + t.length); }); // Key: 1 Length: 2 // Key: 2 Length: 2
ToDictionary
یک شی از یک آرایه را براساس یک تابع انتخاب گر کلیدی مشخصی ایجاد می کند.
Array.prototype.toDictionary = function (keySelector, valueSelector) { var o = {}; var l = this.length; while (l-- > 0) { var key = keySelector(this[l]); if (key == null || key == "") continue; o[key] = valueSelector(this[l]); } return o; };
مثال:
var arr = [1, 2, 3, 4, 5]; var dic = arr.toDictionary(function(t){ return "Num" + t }, function(u){ return u }); // dic = {Num5: 5, Num4: 4, Num3: 3, Num2: 2, Num1: 1}
توابع جمعی LINQ جاوا اسکریپت
Aggregate
یک تابع جمع کننده را روی یک دنباله اعمال می نماید.
Array.prototype.aggregate = Array.prototype.reduce || function (func, seed) { var arr = this.slice(0); var l = this.length; if (seed == null) seed = arr.shift(); for (var i = 0; i < l; i++) seed = func(seed, arr[i], i, this); return seed; };
مثال:
var arr = [1, 2, 3, 4, 5]; var sum = arr.aggregate(function(a, b){ return a + b }, 0); // 15
Min
کمترین مقدار بین مقادیر دنباله را برمی گرداند.
Array.prototype.min = function (s) { s = s || DefaultSelector; var l = this.length; var min = s(this[0]); while (l-- > 0) if (s(this[l]) < min) min = s(this[l]); return min; };
مثال:
var arr1 = [1, 2, 3, 4, 5, 6, 7, 8]; var min1 = arr.min(); // 1 var arr2 = [{Name:"A", Val:1}, {Name:"B", Val:2}]; var min2 = arr2.min(function(t){ return t.Val }); // 1
Max
بیشترین مقدار بین مقادیر یک دنباله را برمی گرداند.
Array.prototype.max = function (s) { s = s || DefaultSelector; var l = this.length; var max = s(this[0]); while (l-- > 0) if (s(this[l]) > max) max = s(this[l]); return max; };
مثال:
var arr1 = [1, 2, 3, 4, 5, 6, 7, 8]; var max1 = arr.max(); // 8 var arr2 = [{Name:"A", Val:1}, {Name:"B", Val:2}]; var max2 = arr2.max(function(t){ return t.Val }); // 2
Sum
مجموع مقادیر یک دنباله عددی را محاسبه می کند.
Array.prototype.sum = function (s) { s = s || DefaultSelector; var l = this.length; var sum = 0; while (l-- > 0) sum += s(this[l]); return sum; };
مثال:
var arr1 = [1, 2, 3, 4, 5, 6, 7, 8]; var sum1 = arr.sum(); // 36 var arr2 = [{Name:"A", Val:1}, {Name:"B", Val:2}]; var sum2 = arr2.sum(function(t){ return t.Val }); // 3
گزاره های LINQ جاوا اسکریپت
Where
مقادیر دنباله را براساس یک گزاره فیلتر می کند.
Array.prototype.where = Array.prototype.filter || function (predicate, context) { context = context || window; var arr = []; var l = this.length; for (var i = 0; i < l; i++) if (predicate.call(context, this[i], i, this) === true) arr.push(this[i]); return arr; };
مثال:
var arr = [1, 2, 3, 4, 5]; var res = arr.where(function(t){ return t > 2 }) ; // [3, 4, 5]
Any
مشخص می کند که آیا المنتی از دنباله وجود دارد یا یک شرط را برقرار می نماید.
Array.prototype.any = function (predicate, context) { context = context || window; var f = this.some || function (p, c) { var l = this.length; if (!p) return l > 0; while (l-- > 0) if (p.call(c, this[l], l, this) === true) return true; return false; }; return f.apply(this, [predicate, context]); };
مثال:
var arr = [1, 2, 3, 4, 5]; var res1 = arr.any(); // true var res2 = arr.any(function(t){ return t > 5 }); // false
All
مشخص می کند که آیا همه المنت های یک دنباله در شرطی صدق می کنند.
Array.prototype.all = function (predicate, context) { context = context || window; predicate = predicate || DefaultPredicate; var f = this.every || function (p, c) { return this.length == this.where(p, c).length; }; return f.apply(this, [predicate, context]); };
مثال:
var arr = [1, 2, 3, 4, 5]; var res = arr.all(function(t){ return t < 6 }); // true
TakeWhile
المنت هایی از دنباله را تا زمانی که یک شرط خاصی درست باشد برمی گرداند و سپس بقیه المنت ها را نادیده می گیرد.
Array.prototype.takeWhile = function (predicate) { predicate = predicate || DefaultPredicate; var l = this.length; var arr = []; for (var i = 0; i < l && predicate(this[i], i) === true ; i++) arr.push(this[i]); return arr; };
مثال:
var arr = [1, 2, 3, 4, 5, 6, 7, 8]; var res = arr.takeWhile(function(t){ return t % 4 != 0 }); // [1, 2, 3]
SkipWhile
المنت های یک دنباله را تا زمانی که شرط به خصوصی صدق کند نادیده می گیرد و سپس باقیمانده المنت ها را برمی گرداند.
Array.prototype.skipWhile = function (predicate) { predicate = predicate || DefaultPredicate; var l = this.length; var i = 0; for (i = 0; i < l; i++) if (predicate(this[i], i) === false) break; return this.skip(i); };
مثال:
var arr = [1, 2, 3, 4, 5, 6, 7, 8]; var res = arr.skipWhile(function(t){ return t & 4 != 0 }) ; // [ 4, 5, 6, 7, 8]
Contains
مشخص می کند که آیا یک دنباله شامل یک المنت خاص می باشد یا خیر.
Array.prototype.contains = function (o, comparer) { comparer = comparer || DefaultEqualityComparer; var l = this.length; while (l-- > 0) if (comparer(this[l], o) === true) return true; return false; };
مثال:
var arr1 = [1, 2, 3, 4, 5]; var res1 = arr.contains(2); // true var arr2 = [{Name:"A", Val:1}, {Name:"B", Val:1}]; var res2 = arr2.contains({Name:"C", Val:1}, function(a, b){ return a.Val == b.Val }) ; // true
توابع تکرار LINQ جاوا اسکریپت
ForEach
یک عمل خاصی را روی هر یک از المنت های آرایه اجرا می کند.
Array.prototype.forEach = Array.prototype.forEach || function (callback, context) { context = context || window; var l = this.length; for (var i = 0; i < l; i++) callback.call(context, this[i], i, this); };
مثال:
var arr = [1, 2, 3, 4, 5]; arr.forEach(function(t){ if(t % 2 ==0) console.log(t); });
DefaultIfEmpty
المنت هایی از یک دنباله مشخص یا یک مقدار مشخص در مجموعه singleton را برمی گرداند اگر که دنباله خالی باشد.
Array.prototype.defaultIfEmpty = function (val) { return this.length == 0 ? [val == null ? null : val] : this; };
مثال:
var arr = [1, 2, 3, 4, 5]; var res = arr.where(function(t){ return t > 5 }).defaultIfEmpty(5); // [5]