Ejemplo n.º 1
0
        /// <summary>
        /// Combine the specified cubes over the common axes
        /// </summary>
        /// <param name="cubes">The set of cubes</param>
        /// <param name="axes">The set of axes to combine upon</param>
        /// <typeparam name="TValueType"></typeparam>
        /// <returns>A new instance of <see cref="ICube{TValueType}"/> containing all of the values from the input cubes</returns>
        /// <exception cref="ArgumentNullException">Thrown if <paramref name="cubes"/> is null</exception>
        /// <exception cref="InvalidOperationException">Thrown if there are no common axes between the cubes</exception>
        public static ICube <TValueType> CombineCubes <TValueType>(
            IEnumerable <ICube <TValueType> > cubes,
            IReadOnlyList <string> axes = null) where TValueType : ICubeValue
        {
            if (cubes == null)
            {
                throw new ArgumentNullException(nameof(cubes));
            }

            var filteredCubes = cubes.Where(cube => cube != null).ToList();

            if (!filteredCubes.Any())
            {
                return(null);
            }

            HashSet <IAxis> commonAxes = null;

            foreach (var cube in filteredCubes)
            {
                if (commonAxes == null)
                {
                    commonAxes = new HashSet <IAxis>(cube.AxisSet);
                }
                else
                {
                    commonAxes = new HashSet <IAxis>(commonAxes.Intersect(cube.AxisSet));
                }
            }

            if (commonAxes.Count == 0)
            {
                throw new InvalidOperationException("Unable to combine cubes - zero common axes");
            }

            IAxis [] axisList;
            if (axes != null)
            {
                var commonAxesAsDictionary = commonAxes.ToDictionary((a) => a.Name, a => a);
                var axesAsHashSet          = new HashSet <string>(axes);
                commonAxes = new HashSet <IAxis>(commonAxes.Where(a => axesAsHashSet.Contains(a.Name)));

                foreach (var axisName in axes)
                {
                    if (!commonAxesAsDictionary.TryGetValue(axisName, out var axis))
                    {
                        throw new InvalidOperationException($"No axis '{axisName}' found on input cubes");
                    }
                }

                axisList = axes.Select(a => commonAxesAsDictionary [a]).ToArray();
            }
            else
            {
                axisList = commonAxes.ToArray();
            }

            var outputCube = new Cube <TValueType>(new AxisSet(axisList));

            var axisNames = new HashSet <string>(axisList.Select(axis => axis.Name));

            foreach (var cube in filteredCubes)
            {
                int [] axisIndices = new int [axisList.Length];
                for (int idx = 0; idx < axisIndices.Length; idx++)
                {
                    axisIndices [idx] = cube.AxisSet.GetIndexOf(axisList [idx].Name);
                }

                object [] keys = new object [axisList.Length];
                foreach (var point in cube)
                {
                    for (int idx = 0; idx < axisIndices.Length; ++idx)
                    {
                        keys [idx] = point.GetAxisValue(axisIndices [idx]);
                    }

                    outputCube.AddItem(keys, point.CubeValue);

                    foreach (var error in cube.ErrorSet)
                    {
                        var filteredErrorKeys = new Dictionary <string, object>();
                        foreach (var axisName in error.ErrorAxes.Where(k => axisNames.Contains(k)))
                        {
                            filteredErrorKeys [axisName] = error.GetErrorKey(axisName);
                        }

                        outputCube.AddError(filteredErrorKeys, error.ErrorMessage);
                    }
                }
            }

            return(outputCube);
        }