using EgwCoreLib.Lux.Core.RestPayload; using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; namespace EgwCoreLib.Lux.Core.MachineCalc { public class Utils { #region Public Methods /// /// Calcolo delle intersezioni Macchine/Tags(Parts) /// /// /// public static List CalculateIntersections(List machineResult) { var results = new List(); if (machineResult != null && machineResult.Count > 0) { int numParts = machineResult.FirstOrDefault()?.NumParts ?? 0; // Step 1: extract workable tags per machine var machineTags = machineResult .ToDictionary( m => m.Name, m => m.PartList .Where(p => p.CalcResult == Enums.PartVerificationResult.MACHINABLE) .ToList() ); var machineNames = machineTags.Keys.ToList(); // Step 2: generate all combinations of machines for (int size = 1; size <= machineNames.Count; size++) { foreach (var combo in GetCombinations(machineNames, size)) { var comboList = combo.ToList(); // Intersection of tags across all machines in this combo var intersectionTags = comboList .Select(name => machineTags[name].Select(p => p.Tag).ToHashSet()) .Aggregate((set1, set2) => { set1.IntersectWith(set2); return set1; }); // Compute per-machine sums of Time for these tags var sums = comboList.Select(name => machineTags[name] .Where(p => intersectionTags.Contains(p.Tag)) .Sum(p => p.Time) ).ToList(); results.Add(new MachineTagDTO { TotParts = numParts, Machines = comboList, Tags = intersectionTags.ToList(), MinTime = sums.Any() ? sums.Min() : 0, MaxTime = sums.Any() ? sums.Max() : 0 }); } } // Step 3: add unique (non-intersecting) tags per machine foreach (var name in machineNames) { var uniqueTags = machineTags[name] .Select(p => p.Tag) .Except(machineNames.Where(n => n != name) .SelectMany(n => machineTags[n].Select(p => p.Tag))) .ToList(); if (uniqueTags.Count > 0) { var sum = machineTags[name] .Where(p => uniqueTags.Contains(p.Tag)) .Sum(p => p.Time); results.Add(new MachineTagDTO { TotParts = numParts, Machines = new List { name }, Tags = uniqueTags, MinTime = sum, MaxTime = sum }); } } } return results; } /// /// Helper generazione combinazioni di items per una data length (Distinct Combinations) /// /// /// /// /// public static IEnumerable> GetCombinations(IEnumerable items, int length) { // Convert to a List to easily access elements by index. List itemList = items.ToList(); int n = itemList.Count; // Base case: length 0 returns a collection containing an empty collection if (length == 0) { yield return Enumerable.Empty(); yield break; } // Check if enough items are available if (length > n) { yield break; } // Call the internal recursive helper function foreach (var combination in GetCombinationsInternal(itemList, length, 0, n)) { yield return combination; } } /// /// Helper generazione permutazioni di items per una data length /// /// /// /// /// public static IEnumerable> GetPermutations(IEnumerable items, int length) { if (length == 1) return items.Select(i => new T[] { i }); return GetCombinations(items, length - 1) .SelectMany(c => items.Where(i => !c.Contains(i)), (c, i) => c.Concat(new T[] { i })); } /// /// Helper calcolo Intersezione lista macchine /// /// /// /// public static IEnumerable IntersectTags(List machines, Func predicate) { return machines .Select(m => m.PartList.Where(predicate).Select(p => p.Tag).ToHashSet()) .Aggregate((set1, set2) => { set1.IntersectWith(set2); return set1; }); } #endregion Public Methods #region Private Methods private static IEnumerable> GetCombinationsInternal( List items, int length, int startIndex, int n) { // Base case: combination of length 1 if (length == 1) { // Select one item from startIndex up to the end for (int i = startIndex; i < n; i++) { yield return new T[] { items[i] }; } yield break; } // Recursive step // Iterate over elements starting from startIndex for (int i = startIndex; i <= n - length; i++) { T currentItem = items[i]; // Recursively find combinations of length - 1 starting from the next index (i + 1) // This is the crucial step that prevents (a,b) and (b,a) foreach (var subCombination in GetCombinationsInternal(items, length - 1, i + 1, n)) { // Prepend the current item to the shorter combinations yield return new T[] { currentItem }.Concat(subCombination); } } } #endregion Private Methods } }