I'm trying to write a C# algorithm that give the list of possible n-partitions from a pool containing x elements.
In order to be more clear, let's say that I have a pool of 6 elements: 1,2,3,4,5,6 (x = 6)
and I should give all partitions of 3 numbers, ie:
1,2,3 and 4,5,6
1,3,4 and 2,5,6
1,2,5 and 3,4,6
1,2,6 and 3,4,5
etc.
The function I'm targeting looks like :
List<List<List<int>>> GetAllPartitions(int x, int n)
EDIT:
What I'm looking for is not combinations... For it, I use this (taken from this site):
public static IEnumerable<IEnumerable<T>> Combinations<T>(this IEnumerable<T> elements, int k)
{
return k == 0
? new[] {new T[0]}
: elements.SelectMany((e, i) =>
elements.Skip(i + 1).Combinations(k - 1).Select(c => (new[] {e}).Concat(c)));
}
Generally I don't do link only answers (and generally SO likes you to show attempts at a solution too), but there is a complete code solution for objects of any type (not just int) already written in c# found here:
http://blogs.msdn.com/b/updownroundnround/archive/2009/12/18/generating-all-partitions-of-a-set-c-implementation.aspx
Note: this will generate all partitions of every length for the set, so you will need to do a simple select on the resulting list to filter it for only your desired "n" length partitions, which can be simply:
var result = from allResults select result where result.length = n || result.length = x-n
For those worried about link death, here is the linked code:
/// <summary>
/// A enumeration of all possible partitions of a set of items.
/// </summary>
/// <typeparam name="T">The type of the items in the set being partitioned.</typeparam>
public sealed class AllPartitionsEnumerable<T> : IEnumerable<IEnumerable<IEnumerable<T>>>
{
/// <summary></summary>
[DebuggerBrowsable(DebuggerBrowsableState.Collapsed)]
private IEnumerable<T> items;
/// <summary>
/// Creates and initializes an instance of the <see cref="AllPartitionsEnumerable{T}"/> type.
/// </summary>
/// <param name="items">The set of items to be partitioned.</param>
public AllPartitionsEnumerable(IEnumerable<T> items)
: base ()
{
this.items = items;
}
/// <summary>
/// Gets an enumerator to iterate over the partitions in this enumeration.
/// </summary>
/// <returns>An instance of <see cref="IEnumerator{T}"/>.</returns>
public IEnumerator<IEnumerable<IEnumerable<T>>> GetEnumerator()
{
return new AllPartitionsEnumerator<T>(this.items);
}
/// <summary>
/// Gets an enumerator to iterate over the partitions in this enumeration.
/// </summary>
/// <returns>An instance of <see cref="IEnumerator{T}"/>.</returns>
IEnumerator IEnumerable.GetEnumerator()
{
return this.GetEnumerator();
}
}
/// <summary>
/// An enumerator to iterate over the items in an instance of <see cref="AllPartitionsEnumerable{T}"/>.
/// </summary>
/// <typeparam name="T">The type of the items in the set being partitioned.</typeparam>
public sealed class AllPartitionsEnumerator<T> : IEnumerator<IEnumerable<IEnumerable<T>>>
{
/// <summary>The original set of items over which partitions are created.</summary>
[DebuggerBrowsable(DebuggerBrowsableState.Never)]
private T[] items;
/// <summary>Flag to indicate if this enumerator has been disposed of.</summary>
[DebuggerBrowsable(DebuggerBrowsableState.Never)]
private bool isDisposed;
/// <summary>Flag to indicate if this enumerator is in its initial state.</summary>
[DebuggerBrowsable(DebuggerBrowsableState.Never)]
private bool isFirst;
/// <summary>The number of partitions in the current selection.</summary>
[DebuggerBrowsable(DebuggerBrowsableState.Never)]
private int nc;
/// <summary>An array of values indicating the number of values in the partition at the specified index.</summary>
[DebuggerBrowsable(DebuggerBrowsableState.Never)]
private int[] p;
/// <summary>An array of indices indicating to which partition the item at the specified index belongs.</summary>
[DebuggerBrowsable(DebuggerBrowsableState.Never)]
private int[] q;
/// <summary>The current partition.</summary>
[DebuggerBrowsable(DebuggerBrowsableState.Never)]
private T[][] current;
/// <summary>
/// Creates and initializes an instance of the <see cref="AllPartitionsEnumerator{T}"/> type.
/// </summary>
/// <param name="items">The original set of items over which partitions are enumerated.</param>
public AllPartitionsEnumerator(IEnumerable<T> items)
: base()
{
if (null == items)
{
throw new ArgumentNullException("items");
}
this.isFirst = true;
this.items = items.ToArray();
this.nc = 0;
this.p = new int[this.items.Length];
this.q = new int[this.items.Length];
this.current = null;
}
/// <summary>
/// Gets the current partition.
/// </summary>
public IEnumerable<IEnumerable<T>> Current
{
get
{
this.CheckIfDisposed();
return this.current;
}
}
/// <summary>
/// Disposes of this enumerator and releases all resources held by it.
/// </summary>
public void Dispose()
{
if (this.isDisposed)
{
return;
}
this.isDisposed = true;
this.items = null;
this.p = null;
this.q = null;
this.nc = 0;
this.current = null;
this.isFirst = true;
}
/// <summary>
/// Gets the current partition.
/// </summary>
object IEnumerator.Current
{
get
{
return this.Current;
}
}
/// <summary>
/// Selects the next item in the set of all partitions.
/// </summary>
/// <returns><c>true</c> if an item was selected; <c>false</c> if we are past the last element.</returns>
public bool MoveNext()
{
this.CheckIfDisposed();
if (this.isFirst)
{
this.isFirst = false;
this.nc = 1;
this.p[0] = this.items.Length;
for (int i = 0; i < this.items.Length; ++i)
{
this.q[i] = this.nc;
}
this.Select();
return true;
}
if (this.nc == this.items.Length )
{
return false;
}
int n = this.items.Length;
int m = n;
int l = this.q[m-1];
while (this.p[l - 1] == 1)
{
this.q[m - 1] = 1;
--m;
l = this.q[m - 1];
}
this.nc += m - n;
this.p[0] = this.p[0] + n - m;
if (l == this.nc)
{
++this.nc;
this.p[this.nc - 1] = 0;
}
this.q[m - 1] = l + 1;
this.p[l - 1] = this.p[l - 1] - 1;
this.p[l] = this.p[l] + 1;
this.Select();
return true;
}
/// <summary>
/// Resets this enumerator to its initial state.
/// </summary>
public void Reset()
{
this.CheckIfDisposed();
this.current = null;
this.isFirst = true;
this.isDisposed = false;
this.p = new int[this.items.Length];
this.q = new int[this.items.Length];
this.nc = 0;
}
/// <summary>
/// Selects the items for the current partition.
/// </summary>
private void Select()
{
this.current = new T[this.nc][];
for (int i = 0; i < this.nc; ++i)
{
int k = 0;
this.current[i] = new T[this.p[i]];
for (int j = 0; j < this.items.Length; ++j)
{
if (this.q[j] == i + 1)
{
this.current[i][k] = this.items[j];
++k;
}
}
}
}
/// <summary>
/// Checks and throws an exception if this enumerator has been disposed.
/// </summary>
private void CheckIfDisposed()
{
if (this.isDisposed)
{
throw new ObjectDisposedException(this.GetType().FullName);
}
}
}
/// <summary>
/// Retrieves all possible partitions of a set of items.
/// </summary>
/// <typeparam name="T">The type of the items in the original set.</typeparam>
/// <param name="items">The original set of items over which partitions are created.</param>
/// <returns>All possible partitions of the items in <paramref name="items"/>.</returns>
public static IEnumerable<IEnumerable<IEnumerable<T>>> AllPartitions<T>(this IEnumerable<T> items)
{
return new AllPartitionsEnumerable<T>(items);
}
Related
Hi everyone. The problem is too long for me to paste it here so I will paste a URL instead. I get 50% invalid returns. I added a check if a cat has hit a deadlock to collect food/soul on that cell. I have been tackling this issue since 6 am and it is 11am now and I am getting to the point of frustration.
Briefly the problem is the following:
Your task is to calculate the food and the souls collected by Kitty or to output that she is deadlocked.
On the first line of the input you will receive the positions of the coder souls ("#"), food ("*") and deadlocks ("x") as string.
On the second line of the input you will receive the path of the Kitty as string with integers separated by single space. Positive means, move to the right, negative means, move to the left.
The starting position will always be at index 0.
The final result is either the souls, food and deadlocks count or a string informing that the Kitty is deadlocked. The format is shown in the zero tests and the example.
# - symbol for coder soul
* - symbol for food
x - symbol for deadlock
More details below:
https://judge.telerikacademy.com/problem/30kitty
string input = Console.ReadLine();
int deadlocks = 0;
string input2 = Console.ReadLine();
string[] output = input2.Split(' ');
int position = 0;
int startposition = 0;
int codersoulscollected = 0;
int foodcollected = 0;
int iterations = Math.Max(input.Length, output.Length);
bool[] isCollected = new bool[input.Length];
for (int i = 0; i <= iterations; i++)
{
startposition += position;
if (startposition < 0)
{
startposition = input.Length + startposition;
}
if (startposition >= input.Length)
{
startposition = startposition - input.Length;
}
char a = input[startposition];
if (a == '#' && (isCollected[startposition] == false))
{
codersoulscollected++;
isCollected[startposition] = true;
}
if (a == '*' && (isCollected[startposition] == false))
{
foodcollected++;
isCollected[startposition] = true;
}
if (a == 'x' && (isCollected[startposition] == false))
{
deadlocks++;
if (startposition % 2 == 0)
{
codersoulscollected--;
isCollected[startposition] = true;
}
else
{
foodcollected--;
isCollected[startposition] = true;
}
}
else if (a == 'x' && (isCollected[startposition] == true))
{
if (startposition % 2 == 0)
{
codersoulscollected++;
}
else
{
foodcollected++;
}
}
if (output.Length == i)
{
break;
}
position = int.Parse(output[i]);
if (foodcollected < 0 || codersoulscollected < 0)
{
Console.WriteLine("You are deadlocked, you greedy kitty!");
Console.WriteLine($"Jumps before deadlock: {i}");
return;
}
}
if (foodcollected >= 0 || codersoulscollected >= 0)
{
Console.WriteLine($"Coder souls collected: {codersoulscollected}\r\nFood collected: {foodcollected}\r\nDeadlocks: {deadlocks}");
}
Since I had some time at my hand, I wrote a simple solution for you which walks you step by step in an OOP manner. Hopefully you can see your problem as well.
This is your cat. It can walk the given amount of steps on a given Path. It also collects food and soul etc.
public class Cat
{
/// <summary>
/// Amount of collected coder souls.
/// </summary>
private int _coderSouls;
/// <summary>
/// Amount of collected food.
/// </summary>
private int _food;
/// <summary>
/// Amount of deadlocks collected.
/// </summary>
private int _deadlocks;
/// <summary>
/// Number of jumps before deadlocking.
/// Starts from -1 because When we set the path
/// The kitty starts from the 0th tile.
/// </summary>
private int _numberOfJumps = -1;
/// <summary>
/// If Cat can still move.
/// </summary>
private bool _deadLocked;
/// <summary>
/// Path to follow.
/// </summary>
private Path _path;
/// <summary>
/// Creates a Kitty
/// </summary>
/// <param name="path">Path for Kitty</param>
public Cat(Path path)
{
SetPath(path);
}
/// <summary>
/// Set the path for Kitty to follow.
/// </summary>
/// <param name="path">Path to follow.</param>
private void SetPath(Path path)
{
_path = path;
Walk(0);
}
/// <summary>
/// Walks the Kitty with the given amount of steps.
/// </summary>
/// <param name="step">Amount of steps</param>
/// <returns>If kitty can move any more.</returns>
public bool Walk(int step)
{
// If Kitty is deadlocked it can not move any more
if (_deadLocked)
{
return false;
}
// Walks the cat with the given step amount
var got = _path.MoveToNext(step);
// Increase the number of Jumps
_numberOfJumps++;
// Rule written in the question
switch (got)
{
case ItemType.CoderSoul:
_coderSouls++;
break;
case ItemType.Food:
_food++;
break;
case ItemType.DeadLock:
_deadlocks++;
var isEven = _path.GetPosition() % 2 == 0;
if (isEven)
{
if (_coderSouls > 0)
{
_coderSouls--;
return true;
}
_deadLocked = true;
return false;
}
if (_food > 0)
{
_food--;
return true;
}
_deadLocked = true;
return false;
}
return true;
}
/// <summary>
/// When Kitty finished moving, Gets Summary.
/// </summary>
/// <returns>Summary of movemebt</returns>
public string Summarize()
{
return _deadLocked ? PrepareDeadLockMessage() : PrepareSummaryMessage();
}
/// <summary>
/// Deadlock message.
/// </summary>
/// <returns>Deadlock message.</returns>
private string PrepareDeadLockMessage()
{
return $"You are deadlocked, you greedy kitty!{Environment.NewLine}Jumps before deadlock: {_numberOfJumps}";
}
/// <summary>
/// Normal finish.
/// </summary>
/// <returns>Normal finish.</returns>
private string PrepareSummaryMessage()
{
return $"Coder souls collected: {_coderSouls}{Environment.NewLine}Food collected: {_food}{Environment.NewLine}Deadlocks: {_deadlocks}";
}
}
This is your path. You have to parse it as it was given in the question.
public class Path
{
private readonly Item[] path;
private int _currentIndex;
public Path(string pathElements)
{
path = pathElements.Select(t => new Item(t)).ToArray();
_currentIndex = 0;
}
public ItemType MoveToNext(int increase)
{
_currentIndex += increase;
if (_currentIndex > path.Length)
{
_currentIndex -= path.Length;
}
if (_currentIndex < 0)
{
_currentIndex += path.Length;
}
return path[_currentIndex].Collect();
}
public int GetPosition()
{
return _currentIndex;
}
}
This is your single item in your given cell.
public class Item
{
/// <summary>
/// Kitty already collected this cell or not?
/// </summary>
public bool IsCollected { get; private set; }
/// <summary>
/// ItemType in this cell
/// </summary>
public ItemType ItemType { get; }
/// <summary>
/// Represents a single item in each cell.
/// </summary>
/// <param name="c">Type of the item decided by char.</param>
public Item(char c)
{
switch (c)
{
case '#':
ItemType = ItemType.CoderSoul;
break;
case '*':
ItemType = ItemType.Food;
break;
case 'x':
ItemType = ItemType.DeadLock;
break;
}
}
/// <summary>
/// Collect the item in this cell.
/// </summary>
/// <returns>The collected item.</returns>
public ItemType Collect()
{
if (IsCollected)
{
return ItemType.None;
}
IsCollected = true;
return ItemType;
}
}
And finally this is your ItemTypes that can be contained in each cell
/// <summary>
/// The type of item located in each single cell.
/// </summary>
public enum ItemType
{
None,
CoderSoul,
Food,
DeadLock,
}
This is how you use this example. Please go through each step with a debugger.
var cat = new Cat(new Path("x#*#*#*"));
var walkinOrder = "1 -1 -1 4";
var intOrder = walkinOrder.Split(' ').Select(int.Parse);
foreach (var step in intOrder) {
if (cat.Walk(step) == false)
{
break;
}
}
Console.WriteLine(cat.Summarize());
Today I was looking for ways to store my Wavefront Models, and hopefully increase performance, too. I wanted to look into serialization, mainly because I had never used it before. In my mind, serialization/deserialization should be faster than parsing and reinitializing a Wavefront model, however, my benchmark shows otherwise.
Here is the code for my benchmark:
using System;
using System.Diagnostics;
using GrimoireTactics.Framework.OpenGL.Modeling;
using GrimoireTactics.Framework.Utilities;
namespace GrimoireDevelopmentKit.DevelopmentKit
{
static class Program
{
/// <summary>
/// The main entry point for the application.
/// </summary>
[STAThread]
static void Main()
{
WavefrontModel model;
Stopwatch benchmark = new Stopwatch();
//
// Benchmark Deserialization
//
// Do a warm up
for (int i = 0; i < 500; i++)
{
model = ResourceCompiler.ReadFromBinaryFile<WavefrontModel>("C:/Users/Krythic/Desktop/Compiled.sfg"); // Sfg is an extension I wanted to use
}
benchmark.Start();
model = ResourceCompiler.ReadFromBinaryFile<WavefrontModel>("C:/Users/Krythic/Desktop/Compiled.sfg"); // Sfg is an extension I wanted to use
benchmark.Stop();
Console.WriteLine("Deserialization: "+ benchmark.Elapsed);
benchmark.Reset();
//
// Benchmark Plain Old Initialization
//
model = new WavefrontModel();
// Do a Warm up
for (int i = 0; i < 500; i++)
{
model.Load("C:/Users/Krythic/Desktop/Closet.obj");
}
benchmark.Start();
model.Load("C:/Users/Krythic/Desktop/Closet.obj");
benchmark.Stop();
Console.WriteLine("Plain Old Initialization: " + benchmark.Elapsed);
Console.Read();
}
}
}
And here is the output:
Here is the code for Serialization and Deserialization(Which I found on Stackoverflow:
using System.IO;
using System.Runtime.Serialization.Formatters.Binary;
namespace GrimoireTactics.Framework.Utilities
{
public class ResourceCompiler
{
/// <summary>
/// Writes the given object instance to a binary file.
/// <para>Object type (and all child types) must be decorated with the [Serializable] attribute.</para>
/// <para>To prevent a variable from being serialized, decorate it with the [NonSerialized] attribute; cannot be applied to properties.</para>
/// </summary>
/// <typeparam name="T">The type of object being written to the XML file.</typeparam>
/// <param name="filePath">The file path to write the object instance to.</param>
/// <param name="objectToWrite">The object instance to write to the XML file.</param>
/// <param name="append">If false the file will be overwritten if it already exists. If true the contents will be appended to the file.</param>
public static void WriteToBinaryFile<T>(string filePath, T objectToWrite, bool append = false)
{
using (Stream stream = File.Open(filePath, append ? FileMode.Append : FileMode.Create))
{
BinaryFormatter binaryFormatter = new BinaryFormatter();
binaryFormatter.Serialize(stream, objectToWrite);
}
}
/// <summary>
/// Reads an object instance from a binary file.
/// </summary>
/// <typeparam name="T">The type of object to read from the XML.</typeparam>
/// <param name="filePath">The file path to read the object instance from.</param>
/// <returns>Returns a new instance of the object read from the binary file.</returns>
public static T ReadFromBinaryFile<T>(string filePath)
{
using (Stream stream = File.Open(filePath, FileMode.Open))
{
BinaryFormatter binaryFormatter = new BinaryFormatter();
return (T)binaryFormatter.Deserialize(stream);
}
}
}
}
And here is my WavefrontModel class:
using System;
using System.Collections.Generic;
using System.IO;
using GrimoireTactics.Framework.OpenGL.Texturing;
using OpenTK;
using OpenTK.Graphics.OpenGL;
namespace GrimoireTactics.Framework.OpenGL.Modeling
{
[Serializable]
public class WavefrontModel
{
public Vector3[] Vertices;
public Vector2[] TexCoords;
public Vector3[] Normals;
public Face[] Faces;
public string ModelSource;
public string Name;
public Material Material;
/// <summary>
/// A static buffer used by all models when they are loaded.
/// </summary>
private static readonly string[] FileBuffer = new string[15];
/// <summary>
/// A static buffer used by all models when they are loaded.
/// </summary>
private static readonly string[] IndiceBuffer = new string[3];
/// <summary>
/// A static buffer used by all models when they are loaded.
/// </summary>
private static readonly FaceIndices[] VerticesIndexBuffer = new FaceIndices[3];
/// <summary>
/// The Triangle Count of this model.
/// </summary>
public int TriCount
{
get
{
return Faces.Length;
}
}
public WavefrontModel()
{
}
public WavefrontModel(string modelPath, Material material)
{
this.ModelSource = modelPath;
this.Material = material;
}
public WavefrontModel(string modelPath)
{
this.ModelSource = modelPath;
this.Material = null;
}
public WavefrontModel(string[] data)
{
this.ModelSource = String.Empty;
this.Material = null;
Load(data);
}
public WavefrontModel(string[] data, Material material)
{
this.ModelSource = String.Empty;
this.Material = material;
Load(data);
}
/// <summary>
/// Loads a model from the desired Wavefront.obj source given
/// at constructor initialization.
/// </summary>
public void Load()
{
Load(this.ModelSource);
}
/// <summary>
/// Loads a model from a Wavefront.obj located on disk.
/// </summary>
/// <param name="file"></param>
public void Load(string file)
{
Parse(File.ReadAllLines(file), this);
}
/// <summary>
/// Initializes this model with the data provided.
/// </summary>
/// <param name="data"></param>
public void Load(string[] data)
{
Parse(data, this);
}
/// <summary>
/// Current Benchmarked time(Warm boot)
/// </summary>
/// <param name="data"></param>
/// <param name="model"></param>
public static void Parse(string[] data, WavefrontModel model)
{
// Create Header
int totalVertices = 0;
int totalNormals = 0;
int totalTextureCoordinates = 0;
int totalFaces = 0;
for (int i = 0; i < data.Length; i++)
{
switch (data[i][0])
{
case 'v': // Geometric Parameter
switch (data[i][1])
{
case ' ': // Detect Vertices
totalVertices++;
break;
case 't': // Detect TexCoords
totalTextureCoordinates++;
break;
case 'n': // Detect Normals
totalNormals++;
break;
}
break;
case 'f':
totalFaces++;
break;
}
}
// Create the Buffers
model.Vertices = new Vector3[totalVertices];
model.Normals = new Vector3[totalNormals];
model.TexCoords = new Vector2[totalTextureCoordinates];
model.Faces = new Face[totalFaces];
// Load the Data
// Iterators
int verticesIterator = 0;
int normalsIterator = 0;
int textureCoordinatesIterator = 0;
int facesIterator = 0;
for (int line = 0; line < data.Length; line++)
{
string[] lineTokens = SplitStringFast(data[line], ' ', FileBuffer);
switch (lineTokens[0])
{
case "v": // Vector
Vector3 vertex = new Vector3
{
X = ParseFloatFast(lineTokens[1]),
Y = ParseFloatFast(lineTokens[2]),
Z = ParseFloatFast(lineTokens[3])
};
model.Vertices[verticesIterator] = vertex;
verticesIterator++;
break;
case "vt": // Texture Coordinate
Vector2 textureCoordinate = new Vector2
{
X = ParseFloatFast(lineTokens[1]), // U
Y = -ParseFloatFast(lineTokens[2]) // V (Inverted)
};
model.TexCoords[textureCoordinatesIterator] = textureCoordinate;
textureCoordinatesIterator++;
break;
case "vn": // Normal
Vector3 normal = new Vector3
{
X = ParseFloatFast(lineTokens[1]),
Y = ParseFloatFast(lineTokens[2]),
Z = ParseFloatFast(lineTokens[3])
};
model.Normals[normalsIterator] = normal;
normalsIterator++;
break;
case "f": // Face (Triangle indices)
for (int i = 0; i < 3; i++)
{
string[] parameters = SplitStringFast(lineTokens[i + 1], '/', IndiceBuffer);
FaceIndices indices = new FaceIndices
{
Vertex = ParseUInt32Fast(parameters[0]) - 1,
Texture = ParseUInt32Fast(parameters[1]) - 1,
Normal = ParseUInt32Fast(parameters[2]) - 1
};
VerticesIndexBuffer[i] = indices;
}
model.Faces[facesIterator] = new Face(VerticesIndexBuffer[0], VerticesIndexBuffer[1], VerticesIndexBuffer[2]);
facesIterator++;
break;
}
}
}
/// <summary>
/// A custom implementation of Int32.Parse. This
/// function is, on average, 5-6x faster than the one
/// offered by .NET. This function assumes that the string
/// given will yield a positive integer.
/// </summary>
/// <param name="value"></param>
/// <returns></returns>
private static int ParseUInt32Fast(string value)
{
int result = 0;
for (int i = 0; i < value.Length; i++)
{
result = 10 * result + (value[i] - 48);
}
return result;
}
/// <summary>
/// A custom implementation of String.Split(). Realistically, this
/// function is not much faster than what .NET offers; it gains speed
/// more from a preset buffer mechanism.
/// </summary>
/// <param name="value"></param>
/// <param name="delimiter"></param>
/// <param name="buffer"></param>
/// <returns></returns>
private static string[] SplitStringFast(string value, char delimiter, string[] buffer)
{
int resultIndex = 0;
int startIndex = 0;
for (int i = 0; i < value.Length; i++)
{
if (value[i] == delimiter)
{
buffer[resultIndex] = value.Substring(startIndex, i - startIndex);
resultIndex++;
startIndex = i + 1;
}
}
buffer[resultIndex] = value.Substring(startIndex, value.Length - startIndex);
return buffer;
}
/// <summary>
/// A custom implementation of Float.Parse. This
/// function is, on average, 5-6x faster than the one
/// offered by .NET
/// </summary>
/// <param name="inputData">The inputData.</param>
/// <returns></returns>
private static float ParseFloatFast(string inputData)
{
float result = 0;
int position = 0;
int inputLength = inputData.Length;
char firstCharacter = inputData[0];
float negativeSign = 1;
if (firstCharacter == '-')
{
negativeSign = -1;
++position;
}
while (true)
{
if (position >= inputLength)
{
return negativeSign * result;
}
firstCharacter = inputData[position++];
if (firstCharacter < '0' || firstCharacter > '9')
{
break;
}
result = (float)((result * 10.0) + (firstCharacter - '0'));
}
float exponent = 0.1f;
while (position < inputLength)
{
firstCharacter = inputData[position++];
result += (firstCharacter - '0') * exponent;
exponent *= 0.1f;
}
return negativeSign * result;
}
/// <summary>
/// Renders the Model using deprecated immediate mode. This
/// function exists only for testing purposes.
/// </summary>
public void Render()
{
GL.Enable(EnableCap.Texture2D);
GL.Color3(Material.AmbientColor);
GL.BindTexture(TextureTarget.Texture2D, Material.Diffuse);
GL.Begin(PrimitiveType.Triangles);
for (int i = 0; i < Faces.Length; i++)
{
for (int index = 0; index < Faces[i].Indices.Length; index++)
{
Vector3 v = Vertices[Faces[i].Indices[index].Vertex];
Vector3 n = Normals[Faces[i].Indices[index].Normal];
Vector2 tc = TexCoords[Faces[i].Indices[index].Texture];
GL.Normal3(n.X, n.Y, n.Z);
GL.TexCoord2(tc.X, tc.Y);
GL.Vertex3(v.X, v.Y, v.Z);
}
}
GL.End();
}
}
}
Sorry for all the code, I just wanted to show you guys everything I was doing. Now, in my mind, deserialization SHOULD be faster than reparsing the model, creating the arrays, etc, etc, etc. So my question is really: why is deserializtaion NOT faster? Is there something that I could do better to make the roles shift, so that Deserialization becomes faster?
For starters try taking the creation of the binary formatter out of the inner loop. Note that "creating the arrays etc, etc, etc" will also be done by the BinaryFormatter when deserialising - there's no magic way to avoid isntantiating the object graph.
Also you could look into faster serialisers such as Protobuf-net. Check out http://maxondev.com/serialization-performance-comparison-c-net-formats-frameworks-xmldatacontractserializer-xmlserializer-binaryformatter-json-newtonsoft-servicestack-text/
I have a result dataset,
Dataset dsResult = new Dataset();
dsResult.Tables[0].Rows.Count = 17
Now i want to loop through data table for first 5 rows and create a dsResult.Tables[1]
and then next 5 more rows to dsResult.Tables[2]
and next 5 more to dsResult.Tables[3]
then last two rows to dsResult.Tables[4]
from below code i am getting number of tables required
decimal remainder = Decimal.Divide(dsResult.Tables[0].Rows.Count, 5);
var numberOfRequests = Math.Ceiling((decimal)remainder);
Or can we do it in SQL
How to genaralize this logic.
Please guide me here.
using Linq this is very simple
var firstFive = dsResult.Tables[0].AsEnumerable().Take(5);
var secondFive = dsResult.Tables[0].AsEnumerable().Skip(5).Take(5);
and so on.
Do not loop, let Linq do it for you.
If later you will need to convert results to a datatables MSDN has very good example on how to
Creating a DataTable From a Query (LINQ to DataSet)
Maybe helps, but I don't recommend use this solution in real project.
// size of chunk
int chunkSize = 5;
// dataset and table variables
DataSet ds = GetDataSet(); // get your DataSet from somewhere
DataTable source = ds.Tables[0], dest;
// total rows
int count = ds.Tables[0].Rows.Count;
int tableCount = (count + 1) / chunkSize;
// create tables (copy structure)
for (int i = 0; i < tableCount; i++)
{
dest = source.Clone();
dest.TableName = source.TableName + "_" + i.ToString();
ds.Tables.Add(dest);
}
// fill tables
int index = 0;
foreach (DataRow row in source.Rows)
{
dest = ds.Tables[1 + index++ / chunkSize];
// copy row (via copying item arrays)
DataRow rowCopy = dest.NewRow();
rowCopy.ItemArray = row.ItemArray;
dest.Rows.Add(rowCopy);
}
Another solution with ChunkReader<T> (class that slices list to parts with fixed length)
ChunkReader
using System;
using System.Collections.Generic;
using System.Linq;
namespace ServiceCore.Helpers
{
/// <summary>
/// чанкер
/// </summary>
public class ChunkReader<T>
{
#region Declarations
private List<T> _data; // данные
private int _pos; // позиция
#endregion
#region Properties
/// <summary>
/// число записей
/// </summary>
public int Count { get { return _data.Count; } }
/// <summary>
/// размер чанка
/// </summary>
public int ChunkSize { get; set; }
/// <summary>
/// число чанков
/// </summary>
public int ChunksCount
{
get
{
int count = _data.Count;
return count == 0 ? 0 : (int)Math.Ceiling((double)count / (double)ChunkSize);
}
}
#endregion
#region Constructors
/// <summary>
/// конструктор
/// </summary>
public ChunkReader()
{
ChunkSize = 20;
}
/// <summary>
/// конструктор
/// </summary>
/// <param name="data"> данные </param>
public ChunkReader(List<T> data)
: this()
{
Init(data);
}
/// <summary>
/// конструктор
/// </summary>
/// <param name="data"> данные </param>
/// <param name="chunkSize"> размер чанка </param>
public ChunkReader(List<T> data, int chunkSize)
: this()
{
ChunkSize = chunkSize;
Init(data);
}
#endregion
#region Private methods
#endregion
#region Protected methods
#endregion
#region Public methods
/// <summary>
/// инициализация
/// </summary>
/// <param name="data"> данные </param>
public void Init(List<T> data)
{
_data = data;
_pos = 0;
}
/// <summary>
/// сбросить текущую позицию
/// </summary>
public void Reset()
{
_pos = 0;
}
/// <summary>
/// прочитать очередной чанк
/// </summary>
/// <param name="chunk"> чанк </param>
/// <returns></returns>
public bool Read(out List<T> chunk)
{
int count = _data.Count;
if (_pos >= count)
{
chunk = null;
return false;
}
else
{
chunk = new List<T>();
int last = _pos + ChunkSize;
for (int i = _pos; i < count && i < last; i++, _pos++)
{
chunk.Add(_data[_pos]);
}
return true;
}
}
#endregion
}
}
Usage:
// create ChunkReader based on DataTable
var chunker = new ServiceCore.Helpers.ChunkReader<DataRow>(ds.Tables[0].Select().ToList(), 5); // 5 - size of chunk
List<DataRow> chunk;
while (chunker.Read(out chunk))
{
// do somethind with chunk of data rows
}
With LINQ you can acheive it in the following way,
int rowCountPerTable = 5; //Number of tables would be based on this
int currPos = 0;
DataTable dt = ds.Tables[0];
DataTable tempDt = dt.Clone();
dt.Rows.OfType<DataRow>().ToList().ForEach(x =>
{
currPos++;
tempDt.ImportRow(x);
if (currPos == rowCountPerTable)
{
currPos = 0;
tempDt.TableName = "Table" + (ds.Tables.Count + 1);
ds.Tables.Add(tempDt);
tempDt = dt.Clone();
}
else if ((dt.Rows.Count - 1) == dt.Rows.IndexOf(x))
{
tempDt.TableName = "Table" + (ds.Tables.Count + 1);
ds.Tables.Add(tempDt);
}
});
Hope this helps...
I have a need for a circular buffer (or other data structure), on which I can do a "ToArray" or similar call to get the current state of the buffer and use whilst the buffer carries on possibly overwriting the values held.
The reason for this use case is that the returned data is passed to a worker thread to process and the idea is to ensure that as little data is overwritten as possible in between the calls. The choice of a circular data structure was ostensibly to reduce the memory usage of the buffer to a fixed value.
I built the data structure below, which up until yesterday was sufficient for my needs. The relevant calls are TakeSnapshot, TakeAll and TakeWeakArraySnapshot which are all variations on the same theme.
The call is made quite frequently when about a 1000 samples of reference types are available.
All the calls result in an out of memory exception at some point. The exception is the TakeWeakArraySnapshot which basically reverts to null midway through using the array (something i guess is to do with the fact that the gc handle is weak?)
Is there a more suitable memory efficient data structure for this use or something I am doing wrong? Would changing the gc handle type to normal help. Is it possible to create a output type that wraps the references (like i attempted to with the weakreference) which would be easily be reclaimed by the garbage collector?
Thanks for reading.
using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics.Contracts;
using System.Threading;
using System.Runtime.InteropServices;
public class WeakArray<T>
{
private GCHandle[] fArray;
public WeakArray(int length)
{
fArray = new GCHandle[length];
for (int i = 0; i < length; i++)
fArray[i] = GCHandle.Alloc(null, GCHandleType.Weak);
}
~WeakArray()
{
if (fArray == null)
return;
int count = fArray.Length;
for (int i = 0; i < count; i++)
{
GCHandle gcHandle = fArray[i];
if (!gcHandle.IsAllocated)
break;
gcHandle.Free();
}
}
public int Length
{
get
{
return fArray.Length;
}
}
public T this[int index]
{
get
{
return (T) fArray[index].Target;
}
set
{
fArray[index].Target = value;
}
}
}
public class OutputData<TDataType>:IEnumerable<TDataType>,IDisposable
{
private TDataType[] Buffer { get; set; }
private readonly object _lock = new object();
public OutputData(ref TDataType[] buffer,long length)
{
Buffer = buffer;
Length = length;
}
public long Length { get; private set; }
/// <summary>
/// Gets the <see cref="`0"/> at the specified index. Throws IndexOutOfRange for an invalid index
/// or returns the default value of the generic type on an empty queue
/// </summary>
/// <value>
/// The <see cref="`0"/>.
/// </value>
/// <param name="i">The item at that index.</param>
/// <returns></returns>
public TDataType this[int i]
{
get
{
lock (_lock)
{
return Length > 0 ? Buffer[i] : default(TDataType);
}
}
}
public IEnumerator<TDataType> GetEnumerator()
{
for (int i = 0; i < Length; i++)
{
yield return Buffer[i];
}
}
IEnumerator IEnumerable.GetEnumerator()
{
return GetEnumerator();
}
public void Dispose()
{
Array.Clear(Buffer,0,Buffer.Length);
}
public void SetLength(int count)
{
Length = count;
}
}
/// <summary>
/// Implements a CircularBuffer that behaves as a queue
/// </summary>
/// <typeparam name="T"></typeparam>
public class FixedCapacityQueue<T>
{
private T[] _buffer;
private T[] _output;
private OutputData<T> _outputData;
/// <summary>
/// Gets the dropped count. This is the number of samples that have been dropped to
/// maintain the fixed size of the datastructure.
/// </summary>
/// <value>
/// The dropped count.
/// </value>
public int DroppedCount { get; protected set; }
/// <summary>
/// The default number of dropped items required to generate a report
/// </summary>
protected const int DroppedFramesBetweenReports = 1000;
/// <summary>
/// The _start. Index of the first element in buffer.
/// </summary>
private int _start;
/// <summary>
/// The _end. Index after the last element in the buffer.
/// </summary>
private int _end;
/// <summary>
/// The _size. Buffer size.
/// </summary>
private int _numberOfItemsInBuffer;
private readonly object _lock = new object();
/// <summary>
/// Gets or sets the name of the buffer.
/// </summary>
/// <value>
/// The name.
/// </value>
public string Name { get; protected set; }
private readonly T _default = default(T);
/// <summary>
/// Initializes a new instance of the <see cref="FixedCapacityQueue{T}" /> class.
/// </summary>
/// <param name="name">The name of the queue.</param>
/// <param name="bufferSize">Size of the buffer.</param>
public FixedCapacityQueue(string name, int bufferSize)
{
Contract.Requires(bufferSize > 0);
Contract.Requires(!String.IsNullOrEmpty(name));
_buffer = new T[bufferSize];
_output = new T[bufferSize];
_outputData = new OutputData<T>(ref _output, 0);
_start = 0;
_end = _numberOfItemsInBuffer == bufferSize ? 0 : _numberOfItemsInBuffer;
Name = String.Format("FixedCapacityQueue for {0}", name);
}
/// <summary>
/// Initializes a new instance of the <see cref="FixedCapacityQueue{T}" /> class.
/// </summary>
/// <param name="name">The nameof the buffer.</param>
/// <param name="bufferSize">Size of the buffer.</param>
/// <param name="data">The data to be added to the queue.</param>
/// <exception cref="System.ArgumentException"></exception>
public FixedCapacityQueue(string name, int bufferSize, ICollection<T> data)
: this(name, bufferSize)
{
Contract.Requires(data != null);
Contract.Requires(bufferSize > 0);
Contract.Requires(data.Count < bufferSize);
foreach (var dataItem in data)
{
Enqueue(dataItem);
}
}
/// <summary>
/// Gets a value indicating whether the queue [is empty].
/// </summary>
/// <value>
/// <c>true</c> if [is empty]; otherwise, <c>false</c>.
/// </value>
public bool IsEmpty
{
get
{
lock (_lock)
{
return _numberOfItemsInBuffer == 0;
}
}
}
/// <summary>
/// Gets a value indicating whether the queue [is full].
/// </summary>
/// <value>
/// <c>true</c> if [is full]; otherwise, <c>false</c>.
/// </value>
public bool IsFull
{
get
{
lock (_lock)
{
return Count == Size;
}
}
}
/// <summary>
/// Gets the number of items currently present in the queue.
/// </summary>
/// <value>
/// The count.
/// </value>
public int Count
{
get
{
lock (_lock)
{
return _numberOfItemsInBuffer;
}
}
}
/// <summary>
/// Gets the declared size of the queue.
/// </summary>
/// <value>
/// The size.
/// </value>
public int Size
{
get
{
lock (_lock)
{
return _buffer.Length;
}
}
}
/// <summary>
/// Dequeues an item from the queue. The expected behaviour is that if a Dequeue operation is
/// requested whilst a queue is empty, the default type of the generic queue is returned.
/// </summary>
/// <returns></returns>
public T Dequeue()
{
lock (_lock)
{
if (IsEmpty) return _default;
var item = _buffer[_start];
_buffer[_start] = _default;
Increment(ref _start);
--_numberOfItemsInBuffer;
return item;
}
}
/// <summary>
/// Enqueues the specified item to the queue.
/// </summary>
/// <param name="toAdd">To add.</param>
public void Enqueue(T toAdd)
{
lock (_lock)
{
if (IsFull)
{
_buffer[_end] = toAdd;
Increment(ref _end);
_start = _end;
DroppedCount++;
//report drops
if (DroppedCount >= DroppedFramesBetweenReports)
{
//EventAndErrorPump.Instance.WriteOnce(1000, ReportLevelEnum.Warning,
// String.Format("{0} FixedQueue Dropped Items: {1} ", Name, DroppedCount));
DroppedCount = 0;
}
}
else
{
_buffer[_end] = toAdd;
Increment(ref _end);
++_numberOfItemsInBuffer;
}
}
}
/// <summary>
/// Increments the provided index variable by one, wrapping
/// around if necessary.
/// </summary>
/// <param name="index"></param>
private void Increment(ref int index)
{
if (++index == Size)
{
index = 0;
}
}
/// <summary>
/// Decrements the provided index variable by one, wrapping
/// around if necessary.
/// </summary>
/// <param name="index"></param>
private void Decrement(ref int index)
{
if (index == 0)
{
index = Size;
}
index--;
}
public void Enqueue(IEnumerable<T> toAdd)
{
lock (_lock)
{
foreach (var dataItem in toAdd)
{
Enqueue(dataItem);
}
}
}
public IEnumerator<T> GetEnumerator()
{
var segments = new ArraySegment<T>[2] {ArrayOne(), ArrayTwo()};
foreach (ArraySegment<T> segment in segments)
{
for (int i = 0; i < segment.Count; i++)
{
yield return segment.Array[segment.Offset + i];
}
}
}
/// <summary>
/// Gets the at the specified index. Throws IndexOutOfRange for an invalid index
/// or returns the default value of the generic type on an empty queue. The head/earliest item index can also be
/// null in the event of a dequeue. If the front of the queue is required,please use the front function instead
/// </summary>
/// <param name="i">The item at that index.</param>
/// <returns></returns>
/// <exception cref="System.IndexOutOfRangeException"></exception>
public T this[int index]
{
get
{
lock (_lock)
{
if (IsEmpty)
{
return _default;
}
if (index >= _numberOfItemsInBuffer)
{
throw new IndexOutOfRangeException(string.Format("Cannot access index {0}. Buffer size is {1}",
index, _numberOfItemsInBuffer));
}
int actualIndex = InternalIndex(index);
return _buffer[actualIndex];
}
}
}
/// <summary>
/// Converts the index in the argument to an index in <code>_buffer</code>
/// </summary>
/// <returns>
/// The transformed index.
/// </returns>
/// <param name='index'>
/// External index.
/// </param>
private int InternalIndex(int index)
{
return _start + (index < (Size - _start) ? index : index - Size);
}
/// <summary>
/// Clears this instance.
/// </summary>
public void Clear()
{
lock (_lock)
{
_numberOfItemsInBuffer = 0;
_start = 0;
_end = 0;
}
}
/// <summary>
/// Takes a snapshot of the queue and returns it. If used in isolation .i.e not in a buffer implementation
/// it will return all the elements of the queue and leave the queue empty.
/// In a buffer implementation , since the buffer could be accepting data at the point of this call; it is a stale
/// snapshot of the queue when the call is made.
/// </summary>
/// <returns></returns>
[Obsolete("Use TakeAllData() instead")]
public T[] TakeSnapshot()
{
lock (_lock)
{
return TakeSnapshot(Count);
}
}
/// <summary>
/// Takes all data available in the queue.
/// </summary>
/// <returns></returns>
public OutputData<T> TakeAll()
{
var count = Count;
if (count <= 0) return null;
lock (_lock)
{
CopyInto(count, _output);
_outputData.SetLength(count);
return _outputData;
}
}
/// <summary>
/// Takes a snapshot of the queue using the count to limit the output to return. In the event that the specified
/// count is larger than the current size of the queue, it will throw an exception. A zero count value will immediately return
/// In a buffer implementation , since the buffer could be accepting data at the point of this call; it is a stale
/// snapshot of the queue when the call is made.
/// </summary>
/// <returns></returns>
[Obsolete("Use TakeAllData(int count) instead")]
public T[] TakeSnapshot(int count)
{
if (count == 0) return null;
lock (_lock)
{
if (count > _numberOfItemsInBuffer)
{
count = _numberOfItemsInBuffer;
//throw new ArgumentOutOfRangeException(String.Format("Queue size is {0}", Size));
}
var output = new T[count];
CopyInto(count, output);
return output;
}
}
private void CopyInto(int count, T[] output)
{
var lastIndex = (_start + count) - 1;
if (lastIndex >= Size)
{
Array.Copy(_buffer, _start, output, 0, Size - _start);
Array.Copy(_buffer, 0, output, Size - _start, (lastIndex%Size) + 1);
}
else
{
Array.Copy(_buffer, _start, output, 0, count);
}
_start = (_start + count)%Size;
_numberOfItemsInBuffer = _numberOfItemsInBuffer - count;
}
public T[] PeekSnapshot()
{
lock (_lock)
{
var count = Count;
var output = new T[count];
for (var i = 0; i < count; i++)
{
output[i] = this[i];
}
return output;
}
}
public T[] PeekSnapshot(int count)
{
if (count == 0) return null;
lock (_lock)
{
if (count > Size)
{
throw new ArgumentOutOfRangeException(String.Format("Queue size is {0}", Size));
}
var output = new T[count];
for (var i = 0; i < count; i++)
{
output[i] = this[i];
}
return output;
}
}
/// <summary>
/// Gets the front of the queue. The earliest item added to the queue.
/// Use this in lieu of checking this[0] as that could be null whilst items still
/// exist in the queue
/// </summary>
/// <value>
/// The front.
/// </value>
public T Front()
{
lock (_lock)
{
return IsEmpty ? _default : _buffer[_start];
}
}
/// <summary>
/// Gets the utilisation of the datastructure i.e % of the datastructure currently in use
/// </summary>
/// <value>
/// The utilisation.
/// </value>
public float Utilisation
{
get
{
lock (_lock)
{
return CalculateUtilisation();
}
}
}
private float CalculateUtilisation()
{
var util = 0f;
if (Size > 0)
{
util = (Count/(float) Size)*100;
}
return util;
}
/// <summary>
/// Returns the latest item in the queue.
/// </summary>
/// <returns></returns>
public T Back()
{
lock (_lock)
{
return Count > 0 ? _buffer[_end - 1] : _default;
;
}
}
public WeakArray<T> TakeWeakArraySnapshot()
{
lock (_lock)
{
var count = Count;
var arr = new WeakArray<T>(count);
for (var i = 0; i < count; i++)
{
arr[i] = Dequeue();
}
return arr;
}
}
/// <summary>
/// Gets the internal array. Use with EXTREME CAUTION! This is not a thread safe operation
/// and should ONLY be used in situations where any modification to the queue is not possible.
/// Modification operations include Enqueing or Dequeing
/// </summary>
/// <returns></returns>
public T[] GetInternalArray()
{
return _buffer;
}
// doing ArrayOne and ArrayTwo methods returning ArraySegment<T> as seen here:
// http://www.boost.org/doc/libs/1_37_0/libs/circular_buffer/doc/circular_buffer.html#classboost_1_1circular__buffer_1957cccdcb0c4ef7d80a34a990065818d
// http://www.boost.org/doc/libs/1_37_0/libs/circular_buffer/doc/circular_buffer.html#classboost_1_1circular__buffer_1f5081a54afbc2dfc1a7fb20329df7d5b
// should help a lot with the code.
#region Array items easy access.
// The array is composed by at most two non-contiguous segments,
// the next two methods allow easy access to those.
private ArraySegment<T> ArrayOne()
{
if (_start < _end)
{
return new ArraySegment<T>(_buffer, _start, _end - _start);
}
else
{
return new ArraySegment<T>(_buffer, _start, _buffer.Length - _start);
}
}
private ArraySegment<T> ArrayTwo()
{
if (_start < _end)
{
return new ArraySegment<T>(_buffer, _end, 0);
}
else
{
return new ArraySegment<T>(_buffer, 0, _end);
}
}
#endregion
}
Most data structure performance and efficiency comes down to the problem you are trying to solve.
I would recommend not to re-implement data structures yourself unless they don't exist already. Things like ngenerics exist exactly to solve those kind of problems.
This is just a sample project but I'm sure there is other types.
I was digging through some code, when suddenly a wild bug appeared...
Ok let's start.
I created this code to represent a position in a script while parsing.
/// <summary>
/// Represents a position in script. (Used for error reporting)
/// </summary>
public sealed class Position
{
/// <summary>
/// Line count.
/// </summary>
public int Line { get; set; }
/// <summary>
/// Character count.
/// </summary>
public int Char { get; set; }
/// <summary>
/// Index data.
/// </summary>
public int Index { get; set; }
/// <summary>
/// Initialize new Position object to standard values.
/// </summary>
public Position()
{
this.Line = 1;
this.Char = 1;
this.Index = 0;
}
/// <summary>
/// Copy a Position object.
/// </summary>
/// <param name="pos"></param>
public Position(Position pos)
{
this.Line = pos.Line;
this.Char = pos.Char;
this.Index = pos.Index;
}
/// <summary>
/// Initialize new Position object to given parameters.
/// </summary>
/// <param name="p_index">The index in stream.</param>
/// <param name="p_line">The line count.</param>
/// <param name="p_char">The character count</param>
public Position(int p_index, int p_line, int p_char)
{
this.Line = p_line;
this.Char = p_char;
this.Index = p_index;
}
/// <summary>
/// Check if 2 Position objects are equal.
/// </summary>
/// <param name="p1">Left operand.</param>
/// <param name="p2">Right operand.</param>
/// <returns>Returns true, if both position objects are equal.</returns>
public static Boolean operator ==(Position p1, Position p2)
{
return
p1.Index == p2.Index &&
p1.Char == p2.Char &&
p1.Line == p2.Line;
}
/// <summary>
/// Check if 2 Position objects are not equal.
/// </summary>
/// <param name="p1">Left operand.</param>
/// <param name="p2">Right operand.</param>
/// <returns></returns>
public static Boolean operator !=(Position p1, Position p2)
{
return !(p1 == p2);
}
public override int GetHashCode()
{
return base.GetHashCode();
}
/// <summary>
/// Equals overload.
/// </summary>
/// <param name="obj"></param>
/// <returns></returns>
public override bool Equals(object obj)
{
if (obj is Position)
return this == (Position)obj;
return false;
}
/// <summary>
/// ToString override.
/// </summary>
/// <returns></returns>
public override string ToString()
{
return String.Format("{0} - {1} - {2}", this.Index, this.Line, this.Char);
}
}
But... When I do something like this:
var pos1 = new Position();
var pos2 = pos1;
pos2.Char = 10;
Then I change the value of pos1.Char too... I don't know this behavior from C#. The other classes behave the same.
The copy constructor did not help.
I use .NET 4.5 and VS 2012 Update 3...
Can someone tell me what causes this behavior? Or atleast how to get arround this behavior...
pos1 is a reference to the new object. By setting pos2 to pos1, you now have two references to the same object. If you want two different objects, you should do
var pos1 = new Position(); // Create a new object
var pos2 = new Position(pos1); // Use your copy constructor
pos2.Char = 10;
Your ´Position´ class is a ´reference type´
When you equal pos2 to pos1 it points to the same memory location.
Changing the property of one object will thus change the other one also as it is the same object
This isn't a bug; this is correct C# behavior. Position is a class, which is a reference type. The assignment var pos2 = pos1; doesn't copy anything, it just creates another reference to the same Position instance.
You want to call your copy constructor like this:
var pos2 = new Position(pos1);