Пропуск колекцій на умовних засадах за допомогою методу skipWhile у Laravel

Перекладено ШІ
Оригінал: Laravel News
Оновлено: 19 липня, 2025
Метод `skipWhile` у Laravel дозволяє ефективно фільтрувати колекції, пропускаючи елементи, поки виконується певна умова. Досліджуйте, як цей метод може змінити підхід до обробки даних і зрозумійте, як він відкриває нові можливості для аналізу в реальному часі

Метод skipWhile у Laravel реалізує умовне фільтрування, пропускаючи елементи колекції, поки задана умова залишається істинною, а після цього включає всі залишкові елементи, як тільки умова перестає діяти

Метод послідовно оцінює кожен елемент, відкидаючи їх до тих пір, поки колбек не поверне значення false:

$numbers = collect([5, 10, 15, 20, 25, 5, 10]);
 
$filtered = $numbers->skipWhile(function ($value) {
    return $value < 20;
});

Якщо умова для будь-якого елемента стає хибною, цей елемент і всі наступні зберігаються, незалежно від того, чи задовольняють вони початкову умову

$scores = collect([45, 55, 65, 75, 85, 40, 90]);
 
$passingGrades = $scores->skipWhile(fn($score) => $score < 70);

Ось приклад системи обробки даних, що демонструє різні застосування skipWhile:

class DataAnalysisService
{
    public function processServerMetrics(Collection $metrics)
    {
        $criticalPeriod = $metrics->skipWhile(function ($metric) {
            return $metric['cpu_usage'] < 80 && $metric['memory_usage'] < 85;
        });
 
        return $criticalPeriod->map(function ($metric) {
            return [
                'timestamp' => $metric['timestamp'],
                'cpu_usage' => $metric['cpu_usage'],
                'memory_usage' => $metric['memory_usage'],
                'alert_level' => $this->calculateAlertLevel($metric),
                'recommended_action' => $this->getRecommendedAction($metric)
            ];
        });
    }
 
    public function analyzeUserBehavior(Collection $sessionData)
    {
        $engagementStart = $sessionData->skipWhile(function ($event) {
            return in_array($event['action'], ['page_load', 'initial_scroll']) && $event['duration'] < 3;
        });
 
        $meaningfulInteractions = $engagementStart->filter(function ($event) {
            return !in_array($event['action'], ['idle', 'background']);
        });
 
        return [
            'engagement_start_time' => $engagementStart->first()['timestamp'] ?? null,
            'total_meaningful_actions' => $meaningfulInteractions->count(),
            'interaction_types' => $meaningfulInteractions->pluck('action')->unique()->values(),
            'average_action_duration' => $meaningfulInteractions->avg('duration')
        ];
    }
 
    public function processFinancialTransactions(Collection $transactions)
    {
        $significantActivity = $transactions->skipWhile(function ($transaction) {
            return abs($transaction['amount']) < 1000 && $transaction['type'] !== 'transfer';
        });
 
        $analysisResults = [
            'first_significant_transaction' => $significantActivity->first(),
            'total_volume' => $significantActivity->sum('amount'),
            'transaction_count' => $significantActivity->count(),
            'risk_indicators' => $this->identifyRiskPatterns($significantActivity)
        ];
 
        return $analysisResults;
    }
 
    public function extractRelevantLogEntries(Collection $logEntries, string $incidentStart)
    {
        $incidentLogs = $logEntries->skipWhile(function ($entry) use ($incidentStart) {
            return $entry['timestamp'] < $incidentStart || $entry['level'] === 'debug';
        });
 
        $categorizedLogs = $incidentLogs->groupBy('level');
 
        return [
            'error_count' => $categorizedLogs->get('error', collect())->count(),
            'warning_count' => $categorizedLogs->get('warning', collect())->count(),
            'critical_errors' => $categorizedLogs->get('error', collect())
                ->filter(fn($log) => str_contains($log['message'], 'CRITICAL'))
                ->values(),
            'timeline' => $incidentLogs->take(50)->values()
        ];
    }
 
    public function processInventoryMovements(Collection $movements)
    {
        $stockCriticalPeriod = $movements->skipWhile(function ($movement) {
            return $movement['quantity_after'] > 100 && $movement['movement_type'] !== 'emergency_restock';
        });
 
        $restockingAnalysis = $stockCriticalPeriod
            ->filter(fn($movement) => $movement['movement_type'] === 'restock')
            ->map(function ($restock) {
                return [
                    'product_id' => $restock['product_id'],
                    'restock_quantity' => $restock['quantity_change'],
                    'time_to_restock' => $this->calculateRestockTime($restock),
                    'supplier' => $restock['supplier_name']
                ];
            });
 
        return [
            'critical_period_start' => $stockCriticalPeriod->first()['timestamp'] ?? null,
            'low_stock_duration' => $this->calculateDuration($stockCriticalPeriod),
            'restock_events' => $restockingAnalysis->values(),
            'average_restock_time' => $restockingAnalysis->avg('time_to_restock')
        ];
    }
 
    public function analyzeSalesPerformance(Collection $salesData)
    {
        $growthPeriod = $salesData->skipWhile(function ($sale) {
            return $sale['daily_revenue'] <= $sale['previous_day_revenue'] || $sale['growth_rate'] < 0.05;
        });
 
        if ($growthPeriod->isEmpty()) {
            return ['status' => 'no_growth_period_found'];
        }
 
        $performanceMetrics = $growthPeriod->map(function ($day) {
            return [
                'date' => $day['date'],
                'revenue' => $day['daily_revenue'],
                'growth_rate' => $day['growth_rate'],
                'customer_acquisition' => $day['new_customers'],
                'conversion_rate' => $day['conversion_rate']
            ];
        });
 
        return [
            'growth_start_date' => $growthPeriod->first()['date'],
            'peak_revenue_day' => $performanceMetrics->sortByDesc('revenue')->first(),
            'average_growth_rate' => $performanceMetrics->avg('growth_rate'),
            'total_new_customers' => $performanceMetrics->sum('customer_acquisition'),
            'growth_consistency' => $this->calculateGrowthConsistency($performanceMetrics)
        ];
    }
 
    private function calculateAlertLevel($metric)
    {
        if ($metric['cpu_usage'] > 95 || $metric['memory_usage'] > 95) {
            return 'critical';
        }
 
        if ($metric['cpu_usage'] > 85 || $metric['memory_usage'] > 90) {
            return 'high';
        }
 
        return 'medium';
    }
 
    private function getRecommendedAction($metric)
    {
        return match($this->calculateAlertLevel($metric)) {
            'critical' => 'Необхідне термінове втручання',
            'high' => 'Масштабування ресурсів або оптимізація процесів',
            'medium' => 'Постійно моніторити',
            default => 'Продовжуйте моніторинг'
        };
    }
 
    private function identifyRiskPatterns($transactions)
    {
        $patterns = [];
 
        if ($transactions->where('amount', '>', 10000)->count() > 3) {
            $patterns[] = 'висока_концентрація_сум';
        }
 
        if ($transactions->where('type', 'international')->count() > 5) {
            $patterns[] = 'незвична_міжнародна_діяльність';
        }
 
        return $patterns;
    }
}

Метод skipWhile особливо ефективний у виявленні точок переходу в послідовних даних, що робить його ідеальним для аналізу часових рядів, виявлення порогів та фільтрацій на основі стану