chunkBy، نسخهٔ کوتاهشدهٔ chunkWhile تو لاراول ۱۳.۳۰
خلاصهٔ کاملتر
لاراول ۱۳.۳۰ متد chunkBy() رو به کالکشنها اضافه کرده. تو مقالهٔ لاراولنیوز اومده که این متد یه میانبره برای رایجترین کاربرد chunkWhile(). تو اون روش باید خودت مقایسهٔ مقدار فعلی رو با آخرین آیتمِ چانک (یعنی همون تیکهای که اون لحظه داره ساخته میشه) بنویسی، در حالی که تنها چیز مهم تو کل اون خط فقط یه اسم فیلد بود. حالا همون رو با یه کلید مینویسی:
$lineItems->chunkWhile(
fn ($value, $key, $chunk) => $value->order_id == $chunk->last()->order_id
);
$lineItems->chunkBy('order_id');کلید از data_get() رد میشه، یعنی نقطه هم کار میکنه و میتونی چیزی مثل chunkBy('address.city') بنویسی تا به آرایهها و آبجکتهای تودرتو برسی. کالبک هم قبوله، اگه بخوای خودت مقدار مقایسه رو بسازی.
مهمترین نکته فرقش با groupBy() هست، چون خروجی هر دو یه شکله و فقط سر ترتیب دیتا با هم اختلاف دارن. chunkBy() فقط آیتمهای چسبیدهبههم رو یکی میکنه:
collect([1, 1, 2, 2, 1, 1])->chunkBy(fn ($v) => $v);
// [[1, 1], [2, 2], [1, 1]]
collect([1, 1, 2, 2, 1, 1])->groupBy(fn ($v) => $v);
// [1 => [1, 1, 1, 1], 2 => [2, 2]]به گفتهٔ نویسنده این باگ نیست که دورش بزنی، دقیقاً همون خاصیتیه که این متد رو ارزون نگه میداره. chunkBy() روی LazyCollection هم هست و تنبلی chunkWhile() رو به ارث برده: هر چانک بهمحض عوضشدن مقدار تحویل داده میشه و بیشتر از یه چانک تو حافظه نمیمونه. برای گرفتن خروجی CSV از چند میلیون ردیف، با groupBy() کل جدول قبل از نوشتهشدن اولین فایل تو حافظه میشینه، ولی با cursor() و orderBy('order_id') اوج مصرف حافظه فقط اندازهٔ بزرگترین سفارشه. یعنی اون orderBy تزئینی نیست، قراردادیه که این متد روش کار میکنه.
دو تا نکته هم خوبه بدونی. اول اینکه مقایسه سختگیر نیست و با == انجام میشه نه ===، پس '1' و 1 و 1.0 همه تو یه چانک میافتن؛ برای دیتای مخلوط بهتره از کالبک یه مقدار نرمالشده برگردونی. دوم اینکه ریزالور برای هر آیتم دو بار اجرا میشه، یک بار روی آیتم فعلی و یک بار روی آخرین آیتم چانک. پس اگه کالبکت سنگینه، مثلاً پارس تاریخ یا هش، مقدار رو از قبل حساب کن.
نکات کلیدی:
- chunkBy() تو لاراول ۱۳.۳۰ اضافه شد و کلید یا کالبک میگیره
- فقط آیتمهای پشتسرهم رو یکی میکنه، برخلاف groupBy() که کل کالکشن رو با هم میبینه
- کلید از data_get() رد میشه، پس نقطهای مثل address.city هم جواب میده
- روی LazyCollection هم کار میکنه و خروجیش LazyCollection از LazyCollection هست
- مقایسه با == انجام میشه نه ===، و ریزالور برای هر آیتم دو بار صدا زده میشه
- مشارکتکننده: JosephSilber تو پیآر ۶۱۳۵۷




