#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"; }
}
}
}