private void ResizeFirstDimension(int[] newShape) { var valuesToAddCount = MultiDimensionalArrayHelper.GetTotalLength(newShape) - MultiDimensionalArrayHelper.GetTotalLength(shape); if (valuesToAddCount > 0) { /* * bool generateUniqueValueForDefaultValue = false; * if (null != Owner) * { * generateUniqueValueForDefaultValue = Owner.GenerateUniqueValueForDefaultValue; * // newly added function should be unique * Owner.GenerateUniqueValueForDefaultValue = true; * }s*/ AddValuesToFirstDimension(newShape, valuesToAddCount); /*if (null != Owner) * { * Owner.GenerateUniqueValueForDefaultValue = generateUniqueValueForDefaultValue; * }*/ } else if (valuesToAddCount < 0)// remove values at the end. { RemoveValuesFromFirstDimension(newShape, valuesToAddCount); } else { Shape = newShape; } }
//TODO: rewrite this to use RemoveAt(index,dimension,length) public virtual void RemoveAt(int index) { VerifyIsNotReadOnly(); if (rank == 1) { var valueToRemove = values[index]; if (FireEvents) { var args = FireCollectionChanging(NotifyCollectionChangeAction.Remove, valueToRemove, index); if (args != null && args.Cancel) { return; } } RemoveAt1D(index); shape[0]--; count = MultiDimensionalArrayHelper.GetTotalLength(shape); if (FireEvents) { FireCollectionChanged(NotifyCollectionChangeAction.Remove, valueToRemove, index, -1); } } else { throw new NotSupportedException("Use Resize"); } }
public void Insert(int index, object value) { if (rank != 1) { throw new NotSupportedException("Use SetValue to set values"); } var newValue = value; if (FireEvents) { var args = FireCollectionChanging(NotifyCollectionChangedAction.Add, newValue, index, singleValueLength); if (args != null) { if (args.Cancel) { return; } newValue = args.Item; } } values.Insert(index, newValue); shape[0]++; count = MultiDimensionalArrayHelper.GetTotalLength(shape); if (FireEvents) { FireCollectionChanged(NotifyCollectionChangedAction.Add, newValue, index, -1, singleValueLength); } }
public virtual void Insert(int index, object value) { VerifyIsNotReadOnly(); if (rank != 1) { throw new NotSupportedException("Use SetValue to set values"); } var newValue = value; if (FireEvents) { var args = FireCollectionChanging(NotifyCollectionChangeAction.Add, newValue, index); if (args != null) { if (args.Cancel) { return; } newValue = args.Items[0]; } } //InsertValues1D(index, newValue); InsertValues1D(newValue, index); shape[0]++; count = MultiDimensionalArrayHelper.GetTotalLength(shape); dirty = true;//update min/max after insert..maybe check if the value we inserted is > max or < min if (FireEvents) { FireCollectionChanged(NotifyCollectionChangeAction.Add, newValue, index, -1); } }
public bool MoveNext() { //instead of using count this should be faster. foreach (var i in array.Shape) { if (i == 0) { return(false); } } return(MultiDimensionalArrayHelper.IncrementIndex(index, array.Shape, array.Rank - 1)); }
/// <summary> /// Creates a new multidimensional array using provided values as 1D array. /// Values in the provided list will used in a row-major order. /// </summary> /// <param name="isReadOnly"></param> /// <param name="isFixedSize"></param> /// <param name="defaultValue"></param> /// <param name="values"></param> /// <param name="shape"></param> public MultiDimensionalArray(bool isReadOnly, bool isFixedSize, object defaultValue, IList values, int[] shape) { if (values.Count != MultiDimensionalArrayHelper.GetTotalLength(shape)) { throw new ArgumentException("Copy constructor shape does not match values"); } IsReadOnly = isReadOnly; IsFixedSize = isFixedSize; DefaultValue = defaultValue; Shape = (int[])shape.Clone(); SetValues(CreateClone(values)); }
private object[] GetDefaultValuesToAdd(int dimension, int length) { var valuesToAddShape = (int[])shape.Clone(); valuesToAddShape[dimension] = length; var newValuesCount = MultiDimensionalArrayHelper.GetTotalLength(valuesToAddShape); var valuesToAdd = new object[newValuesCount]; for (var i = 0; i < newValuesCount; i++) { valuesToAdd[i] = defaultValue; } return(valuesToAdd); }
private void SetDependendVariabeleValues <T>(IVariable variable, IVariableFilter[] filters, IEnumerable <T> values) { IMultiDimensionalArray componentArrayView = CreateComponentArrayFromFilters(variable, filters); //iterate every value of the view set values for all components. IEnumerator enumerator = values.GetEnumerator(); int size = componentArrayView.Count; //this check is to prevent code like f[1] = new[]{1,2,3} where the 2,3 are silently ignored. //if performance penalty is high here the check should go int count = values.Count(); if (count > size) { throw new ArgumentException(string.Format("Number of values to be written to dependent variable '{0}' exceeds argument values range. Got {1} values expected at most {2}.", variable.Name, count, size)); } int[] stride = MultiDimensionalArrayHelper.GetStride(componentArrayView.Shape); var valuesList = values as IList <T>; if (valuesList == null) { valuesList = values.ToList(); } if (!valuesList.Any()) { return; } var valuesListCount = valuesList.Count; //retrieve count once! for (int i = 0, j = 0; i < size; i++, j++) { int[] indexes = MultiDimensionalArrayHelper.GetIndex(i, stride); if (j == valuesListCount) { j = 0; // reset index, repeat from start } componentArrayView[indexes] = valuesList[j]; } }
/// <summary> /// Compute index in filtered multi-dimensional array based on index in parent multi-dimensional array /// </summary> /// <param name="index"></param> /// <returns></returns> private int GetComponentValueIndexInChildComponent(int[] index, int[] stride) { var childIndex = new int[index.Length]; for (var i = 0; i < index.Length; i++) { var argument = Arguments[i]; var argumentParent = (IVariable)Arguments[i].Parent; childIndex[i] = argument.Values.IndexOf(argumentParent.Values[index[i]]); if (childIndex[i] == -1) { return(-1); // argument value is filtered } } return(MultiDimensionalArrayHelper.GetIndex1d(childIndex, stride)); }
public virtual void RemoveAt(int dimension, int index, int length) { VerifyIsNotReadOnly(); if (rank == 1) { var elementsToRemove = length; while (elementsToRemove != 0) { RemoveAt(index); elementsToRemove--; } } else { //move items if (dimension > 0 || index != shape[dimension] - 1) // don't copy when 1st dimension and delete at the end (note: performance) { for (var i = 0; i < count; i++) // TODO: optimize this, probably it is better to iterate in nD array instead of 1d { var currentIndex = MultiDimensionalArrayHelper.GetIndex(i, stride); if ((currentIndex[dimension] < index) || (currentIndex[dimension] >= (shape[dimension] - length))) { continue; } // value is to be moved to a new spot in the array var oldIndexes = (int[])currentIndex.Clone(); oldIndexes[dimension] += length; values[i] = values[MultiDimensionalArrayHelper.GetIndex1d(oldIndexes, stride)]; } } //trim the array var newShape = (int[])shape.Clone(); if (newShape[dimension] > 0) { newShape[dimension] -= length; } Resize(newShape); } }
public virtual int Add(object value) { if (rank == 1) { var index = count; var newValue = value; if (FireEvents) { var args = FireCollectionChanging(NotifyCollectionChangedAction.Add, newValue, index, singleValueLength); if (args != null) { if (args.Cancel) { return(-1); } newValue = args.Item; index = args.Index; //index might be changed by changing listeners forcing a sort. } } values.Insert(index, newValue); if (newValue is INotifyPropertyChanged) { ((INotifyPropertyChanged)newValue).PropertyChanged += Item_PropertyChanged; } shape[0]++; count = MultiDimensionalArrayHelper.GetTotalLength(shape); if (FireEvents) { FireCollectionChanged(NotifyCollectionChangedAction.Add, newValue, index, -1, singleValueLength); } return(index); } throw new NotSupportedException("Use Resize() and this[] to work with array where number of dimensions > 1"); }
private void SetDependendVariabeleValues <T>(IVariable variable, IVariableFilter[] filters, IEnumerable <T> values) { IMultiDimensionalArray componentArrayView = CreateComponentArrayFromFilters(variable, filters); //iterate every value of the view set values for all components. IEnumerator enumerator = values.GetEnumerator(); int size = componentArrayView.Count; int[] stride = MultiDimensionalArrayHelper.GetStride(componentArrayView.Shape); for (int i = 0; i < size; i++) { int[] indexes = MultiDimensionalArrayHelper.GetIndex(i, stride); //travese our values. Reset if we run out of values if (!enumerator.MoveNext()) { enumerator.Reset(); enumerator.MoveNext(); } componentArrayView[indexes] = enumerator.Current; } }
public override object this[params int[] index] { get { if (index.Length == 1 && Rank != 1) // use 1D access { int[] stride = MultiDimensionalArrayHelper.GetStride(Shape); return(parent[GetIndexInParent(MultiDimensionalArrayHelper.GetIndex(index[0], stride))]); } return(parent[GetIndexInParent(index)]); } set { if (index.Length == 1 && Rank != 1) // use 1D access { int[] stride = MultiDimensionalArrayHelper.GetStride(Shape); parent[GetIndexInParent(MultiDimensionalArrayHelper.GetIndex(index[0], stride))] = value; return; } parent[GetIndexInParent(index)] = value; } }
public virtual void RemoveAt(int index) { if (rank == 1) { var valueToRemove = values[index]; if (FireEvents) { var args = FireCollectionChanging(NotifyCollectionChangedAction.Remove, valueToRemove, index, singleValueLength); if (args != null && args.Cancel) { return; } } if (values[index] is INotifyPropertyChanged) { ((INotifyPropertyChanged)values[index]).PropertyChanged -= Item_PropertyChanged; } values.RemoveAt(index); shape[0]--; count = MultiDimensionalArrayHelper.GetTotalLength(shape); if (FireEvents) { FireCollectionChanged(NotifyCollectionChangedAction.Remove, valueToRemove, index, -1, singleValueLength); } } else { throw new NotSupportedException("Use Resize"); } }
/// <summary> /// Resizes array using new lengths of dimensions. /// </summary> /// <param name="newShape"></param> public virtual void Resize(params int[] newShape) { VerifyIsNotReadOnly(); //speed using inserts and remove at the bounds of dimensions... /*if (newShape.Length == Rank) * { * for (int i =0;i<Rank;i++) * { * var delta = newShape[i] - shape[i]; * if (delta > 0) * { * InsertAt(i, shape[i], delta); * } * else if (delta < 0) * { * RemoveAt(i,shape[i]+delta); * } * } * } */ // special case when only the first dimension is altered if (MultiDimensionalArrayHelper.ShapesAreEqualExceptFirstDimension(shape, newShape)) { // just in case, check if we really resizing if (shape[0] == newShape[0]) { return; } ResizeFirstDimension(newShape); return; } var oldShape = shape; var oldStride = stride; // TODO: optimize copy, currently it is very slow and unscalable // create a new defaultValue filled arrayList var newTotalLength = MultiDimensionalArrayHelper.GetTotalLength(newShape); var newValues = CreateValuesList(); for (int i = 0; i < newTotalLength; i++) { newValues.Add(defaultValue); } //var newValues = Enumerable.Repeat(defaultValue, newTotalLength).ToList(); var newStride = MultiDimensionalArrayHelper.GetStride(newShape); // copy old values to newValues if they are within a new shape, otherwise send Changing event for all *removed* values for (var i = 0; i < values.Count; i++) { var oldIndex = MultiDimensionalArrayHelper.GetIndex(i, stride); var isOldIndexWithinNewShape = MultiDimensionalArrayHelper.IsIndexWithinShape(oldIndex, newShape); if (!isOldIndexWithinNewShape) { if (FireEvents) { var args = FireCollectionChanging(NotifyCollectionChangeAction.Remove, values[i], i); if (args != null && args.Cancel) { return; } } continue; } var newValueIndex = MultiDimensionalArrayHelper.GetIndex1d(oldIndex, newStride); newValues[newValueIndex] = values[i]; } // set a new value and send Changing event for all *newly added* values for (var i = 0; i < newValues.Count; i++) { var newIndex = MultiDimensionalArrayHelper.GetIndex(i, newStride); var isNewIndexWithinOldShape = MultiDimensionalArrayHelper.IsIndexWithinShape(newIndex, shape); if (isNewIndexWithinOldShape) { continue; } var newValue = defaultValue; if (FireEvents) { var args = FireCollectionChanging(NotifyCollectionChangeAction.Add, newValue, i); if (args != null) { if (args.Cancel) { return; } newValue = args.Items[0]; } } newValues[i] = newValue; } var oldValues = values; // replace old values by new values SetValues(newValues); Shape = newShape; if (FireEvents) { // send Changed even for all *removed* values for (var i = 0; i < oldValues.Count; i++) { var oldIndex = MultiDimensionalArrayHelper.GetIndex(i, oldStride); var isIndexWithinNewShape = MultiDimensionalArrayHelper.IsIndexWithinShape(oldIndex, newShape); if (!isIndexWithinNewShape) { FireCollectionChanged(NotifyCollectionChangeAction.Remove, oldValues[i], i, -1); } } // send Changing event for all *newly added* values for (var i = 0; i < newValues.Count; i++) { var newIndex = MultiDimensionalArrayHelper.GetIndex(i, oldStride); var isNewIndexWithinOldShape = MultiDimensionalArrayHelper.IsIndexWithinShape(newIndex, oldShape); if (isNewIndexWithinOldShape) { continue; } FireCollectionChanged(NotifyCollectionChangeAction.Add, newValues[i], i, -1); } } }
public virtual void InsertAt(int dimension, int index, int length) { if (rank == 1 && index == count && length == 1) { bool generateUniqueValueForDefaultValue = Owner.GenerateUniqueValueForDefaultValue; Owner.GenerateUniqueValueForDefaultValue = true; Add(defaultValue); Owner.GenerateUniqueValueForDefaultValue = generateUniqueValueForDefaultValue; return; } //resize the array. This can cause a change of stride //copy values etc. Refactor resize and copy data operation? //increment the correct dimensions var newShape = (int[])shape.Clone(); newShape[dimension] += length; // THE REST IS VERY SLOW BECAUSE ALL VALUES ARE COPIED! // compute number of values to be added var valuesToAddShape = (int[])shape.Clone(); valuesToAddShape[dimension] = length; var newValuesCount = MultiDimensionalArrayHelper.GetTotalLength(valuesToAddShape); var valuesToAdd = new ArrayList(); for (var i = 0; i < newValuesCount; i++) { valuesToAdd.Add(defaultValue); } // send Changing events if (FireEvents && valuesToAdd.Count > 0) { var newStride = MultiDimensionalArrayHelper.GetStride(newShape); var valueToAddIndex = new int[rank]; valueToAddIndex[dimension] = index; var i = 0; do { int newIndex1d = MultiDimensionalArrayHelper.GetIndex1d(valueToAddIndex, newStride); var args = FireCollectionChanging(NotifyCollectionChangedAction.Add, defaultValue, newIndex1d, singleValueLength); if (args != null) { if (args.Cancel) { return; } valuesToAdd[i] = args.Item; } i++; } while (MultiDimensionalArrayHelper.IncrementIndex(valueToAddIndex, valuesToAddShape, rank - 1)); } var eventsAreFired = fireEvents; fireEvents = false; Resize(newShape); // TODO: dangerous, Shape and Stride will already change here fireEvents = eventsAreFired; //walk down the values in the underlying array //copy the values to a new spot if the value is to be moved int addedValueIndex = 0; for (var i = count - 1; i >= 0; i--) { var newIndex = MultiDimensionalArrayHelper.GetIndex(i, stride); // getting index one more time is faster than Clone() var oldIndex = MultiDimensionalArrayHelper.GetIndex(i, stride); oldIndex[dimension] -= length; // value is to be moved if (newIndex[dimension] >= index + length) { values[MultiDimensionalArrayHelper.GetIndex1d(newIndex, stride)] = values[MultiDimensionalArrayHelper.GetIndex1d(oldIndex, stride)]; } // new value added, send Changed event if ((newIndex[dimension] >= index) && (newIndex[dimension] < index + length)) { var index1d = MultiDimensionalArrayHelper.GetIndex1d(newIndex, stride); values[index1d] = valuesToAdd[addedValueIndex]; if (FireEvents) { FireCollectionChanged(NotifyCollectionChangedAction.Add, valuesToAdd[addedValueIndex], index1d, -1, singleValueLength); } addedValueIndex++; } } }
private void AddValuesToFirstDimension(int[] newShape, int valuesToAddCount) { var valuesToAdd = new object[valuesToAddCount]; // send Changing events var index1d = values.Count - 1; for (var i = 0; i < valuesToAddCount; i++) { var newValue = defaultValue; if (FireEvents) { index1d++; var args = FireCollectionChanging(NotifyCollectionChangedAction.Add, newValue, index1d, singleValueLength); if (args != null) { if (args.Cancel) { return; } newValue = args.Item; } } valuesToAdd[i] = newValue; // specific case, for 1d we have to generate events one by one! if (rank == 1) { values.Add(newValue); shape[0]++; count = MultiDimensionalArrayHelper.GetTotalLength(shape); if (FireEvents) { FireCollectionChanged(NotifyCollectionChangedAction.Add, newValue, index1d, -1, singleValueLength); } } } if (rank > 1) { // add new values foreach (var o in valuesToAdd) { values.Add(o); } Shape = newShape; if (FireEvents) { // send Changed events index1d = values.Count - valuesToAddCount - 1; for (var i = 0; i < valuesToAddCount; i++) { index1d++; var valueToAdd = valuesToAdd[i]; FireCollectionChanged(NotifyCollectionChangedAction.Add, valueToAdd, index1d, -1, singleValueLength); } } } }
//TODO: change this signature of values object[] this will cause boxing and bad performance probably.. //push the functionality down to the generic subclass. /// <summary> /// Insert a slices of value(s) for a given dimension /// </summary> /// <param name="dimension">Dimensen at which to insert</param> /// <param name="index">Index of insert for dimension</param> /// <param name="length">Length (in the dimensions). In 1D this is ValuesToInsert.Count but not in n-D</param> /// <param name="valuesToInsert">Total values</param> /// <returns></returns> public virtual int InsertAt(int dimension, int index, int length, IList valuesToInsert) { if (length == 0) { return(-1); } //resize the array. This can cause a change of stride //copy values etc. Refactor resize and copy data operation? //increment the correct dimensions var newShape = (int[])shape.Clone(); newShape[dimension] += length; // THE REST IS VERY SLOW BECAUSE ALL VALUES ARE COPIED! // compute number of values to be added var valuesToInsertShape = (int[])shape.Clone(); valuesToInsertShape[dimension] = length; MultiDimensionalArrayHelper.VerifyValuesCountMatchesShape(valuesToInsertShape, valuesToInsert); var newStride = MultiDimensionalArrayHelper.GetStride(newShape); var valueToAddIndex = new int[rank]; valueToAddIndex[dimension] = index; int insertionStartIndex = MultiDimensionalArrayHelper.GetIndex1d(valueToAddIndex, newStride); // send Changing events if (FireEvents) { var args = FireCollectionChanging(NotifyCollectionChangeAction.Add, valuesToInsert, insertionStartIndex, valuesToInsertShape); //TODO: handle changes from changing event..allows for sorting (a little bit) if (args != null) { if (args.Cancel) { return(-1); } if (args.Index != insertionStartIndex && IsAutoSorted) { throw new InvalidOperationException("Sorted array does not allow update of Indexes in CollectionChanging"); } } } if (IsAutoSorted) { //values values to insert have values smaller than MaxValue throw var comparables = valuesToInsert.Cast <IComparable>(); var monotonous = comparables.IsMonotonousAscending(); // first is the smallest value since comparables is monotonous ascending :) var allBiggerThanMaxValue = ((MaxValue == null) || ((MaxValue as IComparable).IsSmaller(comparables.First()))); if (comparables.Count() > 1 && (!allBiggerThanMaxValue || !monotonous)) { throw new InvalidOperationException( "Adding range of values for sorted array is only possible if these values are all bigger than the current max and sorted"); } //get the 'real' insertion indexes..first for 1 value //omg this must be slow...get this faster by //A : using the knowledge that the array was sorted (binarysort) //B : using the type of T by moving this into a virtual method and push it down to a subclass insertionStartIndex = GetInsertionStartIndex(valuesToInsert); index = insertionStartIndex;//review and fix all these indexes..it is getting unclear..work in MDA style.. } //performance increase when adding to the first dimension...no stuff will be moved so not need to go throught the whole array later on bool insertIsAtBoundsOfFirstDimension = dimension == 0 && index == shape[0]; var eventsAreFired = fireEvents; fireEvents = false; Resize(newShape); // TODO: dangerous, Shape and Stride will already change here fireEvents = eventsAreFired; dirty = true;//make sure min/max are set dirty //simple insert...at bounds of first index if (insertIsAtBoundsOfFirstDimension) { var addedValueIndex = 0; do { int newIndex1d = MultiDimensionalArrayHelper.GetIndex1d(valueToAddIndex, newStride); var newValue = valuesToInsert[addedValueIndex]; SetValue1D(newValue, newIndex1d); addedValueIndex++; } while (MultiDimensionalArrayHelper.IncrementIndex(valueToAddIndex, newShape, rank - 1)); //fill it up until the whole new shape is filled..because we are are at the bounds of the first dimension if (FireEvents) { FireCollectionChanged(NotifyCollectionChangeAction.Add, valuesToInsert, insertionStartIndex, -1, valuesToInsertShape); } } else //complex...insert could be everywhere and might have to move stuff in the underlying array.. { //walk down the values in the underlying array //copy the values to a new spot if the value is to be moved int addedValueIndex = valuesToInsert.Count - 1; var newIndex = MultiDimensionalArrayHelper.GetIndex(count - 1, stride); //start at end for (var i = count - 1; i >= 0; i--) { // value is to be moved if (newIndex[dimension] >= index + length) { var oldIndex = (int[])newIndex.Clone(); oldIndex[dimension] -= length; values[MultiDimensionalArrayHelper.GetIndex1d(newIndex, stride)] = values[MultiDimensionalArrayHelper.GetIndex1d(oldIndex, stride)]; //set the 'old' copy to 'null' to prevent unsubscribtion when we replace it by the new value values[MultiDimensionalArrayHelper.GetIndex1d(oldIndex, stride)] = defaultValue; } // new value added if ((newIndex[dimension] >= index) && (newIndex[dimension] < index + length)) { var index1d = MultiDimensionalArrayHelper.GetIndex1d(newIndex, stride); var newValue = valuesToInsert[addedValueIndex]; SetValue1D(newValue, index1d); addedValueIndex--;//walk down because we start at the end } if (i > 0) //decrementing last time won't work { MultiDimensionalArrayHelper.DecrementIndexForShape(newIndex, newShape); } } if (FireEvents) { FireCollectionChanged(NotifyCollectionChangeAction.Add, valuesToInsert, insertionStartIndex, -1, valuesToInsertShape); } } return(index);//this might be wrong..the index might have changed }
protected virtual int GetInsertionStartIndex(IList valuesToInsert) { return(MultiDimensionalArrayHelper.GetInsertionIndex((IComparable)valuesToInsert[0], values.Cast <IComparable>().ToList())); }
public override string ToString() { return(MultiDimensionalArrayHelper.ToString(this)); }
public virtual object this[params int[] index] { get { if (index.Length != rank) { if (index.Length == 1) // use 1D { return(values[index[0]]); } throw new ArgumentException("Invalid number of indexes"); } if (index.Length == 1) // performance improvement { return(values[index[0]]); } return(values[MultiDimensionalArrayHelper.GetIndex1d(index, stride)]); } set { VerifyIsNotReadOnly(); //exception single dimensional access to More dimensional array used 1d array if (index.Length != rank) { /* * if (index.Length == 1) // use 1D * { * ((IList)this)[index[0]] = value; * dirty = true; * * //todo: collectionchanged etc * return; * } */ throw new ArgumentException("Invalid number of indexes"); } var index1d = MultiDimensionalArrayHelper.GetIndex1d(index, stride); var newValue = value; var newIndex = index1d; if (values[index1d] == value) { return; // do nothing, value is the same as old value } // log.DebugFormat("Value before Replace: {0}", this); if (FireEvents) { var args = FireCollectionChanging(NotifyCollectionChangeAction.Replace, value, index1d); if (args != null) { if (args.Cancel) { return; } newValue = args.Items[0]; newIndex = args.Index; } } if (IsAutoSorted) { if (newIndex != index1d) { throw new InvalidOperationException("Updating indexes in collectionChanging is not supported for AutoSortedArrays"); } //value or newValue (possible changed by changingEvent...) var oldIndex = index1d; newIndex = MultiDimensionalArrayHelper.GetInsertionIndex((IComparable)value, values.Cast <IComparable>().ToList()); if (newIndex > oldIndex) { newIndex--; //if value is currently left of the new index so our insert should be on index one less.. } } //actual set values... SetValue1D(newValue, index1d); //move values to correct location if necessary if (newIndex != index1d) { Move(0, index1d, 1, newIndex, false); } dirty = true; if (FireEvents) { FireCollectionChanged(NotifyCollectionChangeAction.Replace, value, newIndex, index1d); } // log.DebugFormat("Value after Replace: {0}", this); } }
/// <summary> /// Prepares the Multidimensional array of function. Expands dimensions where needed. /// TODO: this and above methods seem to be redundant /// /// TODO: shouldn't it happen in Function? /// </summary> /// <param name="function"></param> /// <param name="filters"></param> /// <returns></returns> private IMultiDimensionalArray CreateComponentArrayFromFilters(IFunction function, IList <IVariableFilter> filters) { if (filters.Count == 0) { return(FunctionValues[Functions.IndexOf(function)]); } var variable = (IVariable)function; // HACK: will create generic view. based on maxInt IMultiDimensionalArrayView view = FunctionValues[Functions.IndexOf(variable)].Select(0, int.MinValue, int.MaxValue); // check if we have aggregation filters, if yes - return a new array, otherwise return a view based on existing array // probably it should be always a view based on existing array, even when aggregation is used if (filters.Any(f => f is VariableAggregationFilter)) { var filterVariableIndex = new Dictionary <VariableAggregationFilter, int>(); foreach (VariableAggregationFilter filter in filters.OfType <VariableAggregationFilter>()) { filterVariableIndex[filter] = variable.Arguments.IndexOf(filter.Variable); } // calculate shape of the resulting array var shape = (int[])view.Shape.Clone(); foreach (VariableAggregationFilter filter in filters.OfType <VariableAggregationFilter>()) { shape[filterVariableIndex[filter]] = filter.Count; } // now fill in values into the resulting array IMultiDimensionalArray result = variable.CreateStorageArray(); result.Resize(shape); int totalLength = MultiDimensionalArrayHelper.GetTotalLength(shape); for (int i = 0; i < totalLength; i++) { int[] targetIndex = MultiDimensionalArrayHelper.GetIndex(i, result.Stride); // calculate index in the source array var sourceIndex = (int[])targetIndex.Clone(); foreach (VariableAggregationFilter filter in filters.OfType <VariableAggregationFilter>()) { int filterArgumentIndex = filterVariableIndex[filter]; sourceIndex[filterArgumentIndex] = GetSourceIndex(filter, targetIndex[filterArgumentIndex]); } result[targetIndex] = view[sourceIndex]; // copy value (only required) } view = result.Select(0, int.MinValue, int.MaxValue); } //use variable filters that are relevant to make a selection IEnumerable <IVariableFilter> relevantArgumentFilters = filters.OfType <IVariableFilter>().Where( f => (f is IVariableValueFilter || f is VariableIndexRangesFilter || f is VariableIndexRangeFilter) && (f.Variable == function || function.Arguments.Contains(f.Variable))); foreach (IVariableFilter variableFilter in relevantArgumentFilters) { //determine indexes for this variable..get in a base class? int[] indexes = GetArgumentIndexes(variableFilter); if (function.IsIndependent && variableFilter.Variable == function) { view.SelectedIndexes[0] = indexes; // indepedent variable always dim 0 } else if (function.Arguments.Contains(variableFilter.Variable)) { int dimensionIndex = function.Arguments.IndexOf(variableFilter.Variable); view.SelectedIndexes[dimensionIndex] = indexes; } } //reduce the view for reduce filters. foreach (VariableReduceFilter filter in filters.OfType <VariableReduceFilter>()) { int index = function.Arguments.IndexOf(filter.Variable); if (index != -1) { view.Reduce[index] = true; } } return(view); }
public virtual object this[params int[] index] { get { if (index.Length != rank) { if (index.Length == 1) // use 1D { return(values[index[0]]); } throw new ArgumentException("Invalid number of indexes"); } if (index.Length == 1) // performance improvement { return(values[index[0]]); } return(values[MultiDimensionalArrayHelper.GetIndex1d(index, stride)]); } set { //exception single dimensional access to More dimensional array used 1d array if (index.Length != rank) { /* * if (index.Length == 1) // use 1D * { * ((IList)this)[index[0]] = value; * dirty = true; * * //todo: collectionchanged etc * return; * } */ throw new ArgumentException("Invalid number of indexes"); } var index1d = MultiDimensionalArrayHelper.GetIndex1d(index, stride); var newValue = value; var newIndex = index1d; var oldValue = values[index1d]; if (values[index1d] == value) { return; // do nothing, value is the same as old value } // log.DebugFormat("Value before Replace: {0}", this); if (FireEvents) { var args = FireCollectionChanging(NotifyCollectionChangedAction.Replace, value, index1d, singleValueLength); if (args != null) { if (args.Cancel) { return; } newValue = args.Item; newIndex = args.Index; } } values[index1d] = newValue; if (newIndex != index1d) { if (Rank > 1) { throw new NotSupportedException("Replacing index in CollectionChanging event works only for 1D arrays for now."); } if (newIndex != index1d) { Move(0, index1d, 1, newIndex); } } dirty = true; if (FireEvents) { FireCollectionChanged(NotifyCollectionChangedAction.Replace, oldValue, index1d, newIndex, singleValueLength); } // log.DebugFormat("Value after Replace: {0}", this); } }