#region License Information /* HeuristicLab * Copyright (C) 2002-2013 Heuristic and Evolutionary Algorithms Laboratory (HEAL) * * This file is part of HeuristicLab. * * HeuristicLab is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * HeuristicLab is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with HeuristicLab. If not, see . */ #endregion using System; using System.Collections.Generic; using System.Linq; using System.Windows.Forms; using HeuristicLab.DataImporter.Data; using HeuristicLab.DataImporter.Data.CommandBase; using HeuristicLab.DataImporter.Data.Model; using HeuristicLab.Persistence.Default.CompositeSerializers.Storable; namespace HeuristicLab.DataImporter.Command { [StorableClass] [ViewableCommandInfo("Align ColumnGroups", 2, ColumnGroupState.Sorted, "ColumnGroup Commands", Position = 4)] public class AlignColumnGroupsCommand : DataSetCommandWithAffectedColumnGroupsBase { private ColumnGroup newColumnGroup1; private ColumnGroup newColumnGroup2; private ColumnGroup oldColumnGroup1; private ColumnGroup oldColumnGroup2; private int removePos1; private int removePos2; [StorableConstructor] protected AlignColumnGroupsCommand(bool deserializing) : base(deserializing) { } public AlignColumnGroupsCommand(DataSet dataSet, List affectedColumnGroupNames) : base(dataSet, affectedColumnGroupNames) { } public override void Execute() { base.Execute(); this.oldColumnGroup1 = this.DataSet.GetColumnGroup(AffectedColumnGroupNames[0]); this.oldColumnGroup2 = this.DataSet.GetColumnGroup(AffectedColumnGroupNames[1]); this.removePos1 = this.DataSet.IndexOfColumnGroup(oldColumnGroup1); this.removePos2 = this.DataSet.IndexOfColumnGroup(oldColumnGroup2); if (!oldColumnGroup1.Columns.Any() || !oldColumnGroup2.Columns.Any()) return; if (oldColumnGroup1.SortedColumnsCount < 1 || oldColumnGroup1.SortedColumnsCount != oldColumnGroup2.SortedColumnsCount) throw new CommandExecutionException("Both ColumnGroups must be sorted by at least one column and must be sorted by the same number of columns.", this); for (int i = 0; i < oldColumnGroup1.SortedColumnsCount; i++) { if (this.oldColumnGroup1.SortOrdersForColumns.ElementAt(oldColumnGroup1.SortedColumnIndexes.ElementAt(i)) != this.oldColumnGroup2.SortOrdersForColumns.ElementAt(oldColumnGroup2.SortedColumnIndexes.ElementAt(i))) throw new CommandExecutionException("Both ColumnGroups must be sorted in the same direction.", this); if (this.oldColumnGroup1.Columns.ElementAt(oldColumnGroup1.SortedColumnIndexes.ElementAt(i)).DataType != this.oldColumnGroup2.Columns.ElementAt(oldColumnGroup2.SortedColumnIndexes.ElementAt(i)).DataType) throw new CommandExecutionException("Both ColumnGroups must be sorted by columns of the same type", this); } foreach (int sortColIndex in oldColumnGroup1.SortedColumnIndexes) { if (oldColumnGroup1.Columns.ElementAt(sortColIndex).ContainsNullValues) throw new CommandExecutionException("KeyColumn " + oldColumnGroup1.GetColumn(sortColIndex).Name + " not contain null values.", this); } foreach (int sortColIndex in oldColumnGroup2.SortedColumnIndexes) { if (oldColumnGroup2.Columns.ElementAt(sortColIndex).ContainsNullValues) throw new CommandExecutionException("KeyColumn " + oldColumnGroup1.GetColumn(sortColIndex).Name + " must not contain null values.", this); } SampleColumnGroup(); DataSet.ReplaceColumnGroup(removePos1, newColumnGroup1); DataSet.ReplaceColumnGroup(removePos2, newColumnGroup2); newColumnGroup1 = null; newColumnGroup2 = null; DataSet.FireChanged(); } public override void UndoExecute() { base.UndoExecute(); DataSet.ReplaceColumnGroup(removePos1, oldColumnGroup1); DataSet.ReplaceColumnGroup(removePos2, oldColumnGroup2); oldColumnGroup1 = null; oldColumnGroup2 = null; DataSet.FireChanged(); } public void SampleColumnGroup() { var keyColumnIndex1 = oldColumnGroup1.SortedColumnIndexes; var keyColumnIndex2 = oldColumnGroup2.SortedColumnIndexes; this.newColumnGroup1 = new ColumnGroup(this.oldColumnGroup1.Name); this.newColumnGroup2 = new ColumnGroup(this.oldColumnGroup2.Name); this.newColumnGroup1.SortedColumnIndexes = this.oldColumnGroup1.SortedColumnIndexes; this.newColumnGroup2.SortedColumnIndexes = this.oldColumnGroup2.SortedColumnIndexes; ColumnBase column; foreach (ColumnBase col in this.oldColumnGroup1.Columns) { column = col.CreateCopyOfColumnWithoutValues(); column.SortOrder = col.SortOrder; this.newColumnGroup1.AddColumn(column); } foreach (ColumnBase col in this.oldColumnGroup2.Columns) { column = col.CreateCopyOfColumnWithoutValues(); column.SortOrder = col.SortOrder; this.newColumnGroup2.AddColumn(column); } int compareDirection = this.oldColumnGroup1.SortOrdersForColumns.ElementAt(oldColumnGroup1.SortedColumnIndexes.ElementAt(0)) == SortOrder.Ascending ? -1 : +1; int i = 0; int j = 0; IComparable[] row1; IComparable[] row2; while (i < oldColumnGroup1.RowCount && j < oldColumnGroup2.RowCount) { //key1 < key2 int cmpResult = CompareRows(oldColumnGroup1, i, keyColumnIndex1, oldColumnGroup2, j, keyColumnIndex2); if (cmpResult == compareDirection) {//keyColumn1.GetValue(i).CompareTo(keyColumn2.GetValue(j)) == compareDirection) { row1 = this.oldColumnGroup1.GetRow(i); row2 = this.oldColumnGroup2.GetEmptyRow(); CopyRow(row1, keyColumnIndex1, row2, keyColumnIndex2);// row2[keyColumnIndex2] = row1[keyColumnIndex1]; i++; } //key1 == key2 else if (/*keyColumn1.GetValue(i).CompareTo(keyColumn2.GetValue(j))*/ cmpResult == 0) { row1 = this.oldColumnGroup1.GetRow(i); row2 = this.oldColumnGroup2.GetRow(j); bool columnGroup1Dup = false; bool columnGroup2Dup = false; if (i + 1 < oldColumnGroup1.RowCount) { columnGroup1Dup = CompareRows(oldColumnGroup1, i, keyColumnIndex1, oldColumnGroup1, i + 1, keyColumnIndex1) == 0; } if (j + 1 < oldColumnGroup2.RowCount) { columnGroup2Dup = CompareRows(oldColumnGroup2, j, keyColumnIndex2, oldColumnGroup2, j + 1, keyColumnIndex2) == 0; } if (columnGroup1Dup && !columnGroup2Dup) { i++; // only advance to the row of the duplicate } else if (!columnGroup1Dup && columnGroup2Dup) { j++; } else { // either both are a duplicates or neither is i++; j++; } } //key1 > key2 else { row1 = this.oldColumnGroup1.GetEmptyRow(); row2 = this.oldColumnGroup2.GetRow(j); CopyRow(row2, keyColumnIndex2, row1, keyColumnIndex1);// row1[keyColumnIndex1] = row2[keyColumnIndex2]; j++; } this.newColumnGroup1.AddRow(row1); this.newColumnGroup2.AddRow(row2); } for (; i < oldColumnGroup1.RowCount; i++) { this.newColumnGroup1.AddRow(this.oldColumnGroup1.GetRow(i)); this.newColumnGroup2.AddRow(this.oldColumnGroup2.GetEmptyRow()); CopyRow(newColumnGroup2.GetRow(newColumnGroup2.RowCount - 1), keyColumnIndex2, oldColumnGroup1.GetRow(i), keyColumnIndex1); ChangeRow(newColumnGroup2, newColumnGroup2.RowCount - 1, keyColumnIndex2, oldColumnGroup1, i, keyColumnIndex1); } for (; j < oldColumnGroup2.RowCount; j++) { this.newColumnGroup1.AddRow(oldColumnGroup1.GetEmptyRow()); this.newColumnGroup2.AddRow(oldColumnGroup2.GetRow(j)); ChangeRow(newColumnGroup1, newColumnGroup1.RowCount - 1, keyColumnIndex1, oldColumnGroup2, j, keyColumnIndex2); } } private void ChangeRow(ColumnGroup destGroup, int destRowIndex, IEnumerable destColumnIndexes, ColumnGroup srcGroup, int srcRowIndex, IEnumerable srcColumnIndexes) { foreach (var indexPair in Zip(destColumnIndexes, srcColumnIndexes, (d, s) => new { DestIndex = d, SrcIndex = s })) { destGroup.GetColumn(indexPair.DestIndex).ChangeValue(destRowIndex, srcGroup.GetColumn(indexPair.SrcIndex).GetValue(srcRowIndex)); } } private void CopyRow(IComparable[] src, IEnumerable srcIndexes, IComparable[] dest, IEnumerable destIndexes) { if (srcIndexes.Count() != destIndexes.Count()) throw new ArgumentException(); foreach (var indexPair in Zip(srcIndexes, destIndexes, (k, l) => new { First = k, Second = l })) { dest[indexPair.Second] = src[indexPair.First]; } } int CompareRows(ColumnGroup oldColumnGroup1, int i, IEnumerable keyColumnIndex1, ColumnGroup oldColumnGroup2, int j, IEnumerable keyColumnIndex2) { if (keyColumnIndex1.Count() != keyColumnIndex2.Count()) throw new ArgumentException(); var valuePairs = from x in Zip(from index in keyColumnIndex1 select oldColumnGroup1.GetColumn(index).GetValue(i), from index in keyColumnIndex2 select oldColumnGroup2.GetColumn(index).GetValue(j), (k, l) => new { First = k, Second = l }) select x; foreach (var p in valuePairs) { var result = p.First.CompareTo(p.Second); if (result != 0) return result; } return 0; } private static IEnumerable Zip (IEnumerable first, IEnumerable second, Func resultSelector) { using (IEnumerator e1 = first.GetEnumerator()) using (IEnumerator e2 = second.GetEnumerator()) while (e1.MoveNext() && e2.MoveNext()) yield return resultSelector(e1.Current, e2.Current); } public override string Description { get { return "Align column groups"; } } } }