Copying static list to local temp list - c#

Hello I have some static lists, and I have lots of websocket connection and uptading these lists. But in paribuMiktarHesaplama() function, I want to use local temp lists to not change my static lists. But when anything changes on local list , its also effecting my static lists. I didnt any assignment, why its changing and How can I fix ?
static List<decimal> p_btcTlAskPrice = new List<decimal>(new decimal[2]);
static List<decimal> p_btcTlAskQuantity = new List<decimal>(new decimal[2]);
static List<decimal> b_btcUsdtBidPrice = new List<decimal>(new decimal[20]);
static List<decimal> b_btcUsdtBidQuantity = new List<decimal>(new decimal[20]);
/// and more list here...
Static lists
public static (decimal,int,decimal,decimal,decimal) FindMin(decimal paribuPrice, decimal paribuAmount, decimal binancePrice,decimal binanceAmount,decimal usdtTryPrice, decimal usdtTryAmount)
{
decimal paribuTotal,binanceTotal,usdtTotal;
decimal enkucuk;
int enkucukList;
paribuTotal = paribuPrice* paribuAmount/usdtTryPrice;
binanceTotal = binancePrice * binanceAmount;
enkucuk = usdtTryAmount;
usdtTotal = usdtTryAmount;
enkucukList = 3;
if (paribuTotal < enkucuk) {
enkucuk = paribuTotal;
enkucukList = 1;
}
if (binanceTotal < enkucuk) {
enkucuk = binanceTotal;
enkucukList = 2;
}
return (enkucuk, enkucukList,paribuTotal,binanceTotal,usdtTotal);
}
public static void paribuMiktarHesaplama(List<decimal> paribuPrice,List<decimal> paribuAmount,List<decimal> binancePrice,List<decimal> binanceAmount)
{
var i = 0; var j = 0; var k = 0; decimal enKucuk = 0 ; int enKucukList; decimal totalAmount=0; decimal enKucukParibu = 0; decimal enKucukBinance = 0; decimal enKucukUsdt = 0;
var tempParibuAmount = paribuAmount; var tempBinanceAmount = binanceAmount; var tempUsdtTryAmount = b_usdtTryBidQuantity;
var tempParibuPrice = paribuPrice; var tempBinancePrice = binancePrice; var tempUsdtTryPrice = b_usdtTryBidPrice;
while (true)
{
if (tempParibuPrice[i] * paribuFee < tempBinancePrice[j] / binanceFee * tempUsdtTryPrice[k] / binanceFee)
{//en küçük miktarın çıkarılması lazım
var returnTuple = FindMin(tempParibuPrice[i], tempParibuAmount[i], tempBinancePrice[j], tempBinanceAmount[j], tempUsdtTryPrice[k], tempUsdtTryAmount[k]);
enKucuk = returnTuple.Item1;
enKucukList = returnTuple.Item2;
enKucukParibu = returnTuple.Item3;
enKucukBinance = returnTuple.Item4;
enKucukUsdt = returnTuple.Item5;
totalAmount += enKucuk; // dolar cinsinden
if (enKucukList == 1)
{
//paribu
tempBinanceAmount[j] = (enKucukBinance - enKucuk)/binancePrice[j];
tempUsdtTryAmount[k] = (enKucukUsdt - enKucuk);
tempParibuAmount.RemoveAt(0);
tempParibuPrice.RemoveAt(0);
//i++;
}
else if (enKucukList == 2)
{
//binance
tempParibuAmount[i] = (enKucukParibu - enKucuk ) * b_usdtTryBidPrice[k];
tempUsdtTryAmount[k] = (enKucukUsdt - enKucuk);
tempBinanceAmount.RemoveAt(0);
tempBinancePrice.RemoveAt(0);
//j++;
}
else
{
//tether
tempBinanceAmount[j] = (enKucukBinance - enKucuk) / binancePrice[j];
tempParibuAmount[i] = (enKucukParibu - enKucuk) * b_usdtTryBidPrice[k]/paribuPrice[i];
tempUsdtTryAmount.RemoveAt(0);
tempUsdtTryPrice.RemoveAt(0);
//k++;
}
}
else
{
break;
}
}
Console.WriteLine($"alınacak miktar {totalAmount} fiyatlar paribu {paribuPrice[i]} binance {binancePrice[j]} usdt {b_usdtTryBidPrice[k]}");
}
functions
p_btcTlAskPrice[0] = 600;
p_btcTlAskQuantity[0] = 60;
b_btcUsdtBidPrice[0] = 100;
b_btcUsdtBidQuantity[0] = 80;
b_usdtTryBidPrice[0] = 7;
b_usdtTryBidQuantity[0] = 500;
p_btcTlAskPrice[1] = 650;
p_btcTlAskQuantity[1] = 100;
b_btcUsdtBidPrice[1] = 95;
b_btcUsdtBidQuantity[1] = 50;
b_usdtTryBidPrice[1] = 6.8m;
b_usdtTryBidQuantity[1] = 10000;
paribuMiktarHesaplama(p_btcTlAskPrice, p_btcTlAskQuantity, b_btcUsdtBidPrice, b_btcUsdtBidQuantity);

var tempParibuAmount = paribuAmount
is an assignment that takes the reference of the List you passed. What you need to do is to create a copy of the paribuAmount and store that copy instead:
var tempParibuAmount = new List<decimal>(paribuAmount)
Do that instead for every temp list you create

Related

How to find max value from struct?

public struct nariai
{
public string vardas;
public string pavarde;
public double eurai;
public double centai;
public double suma;
};
static void Main(string[] args)
{
double islaidos;
double surinktiPinigai = 0;
StreamReader failas = new StreamReader("nariai.txt");
string a = failas.ReadLine();
int nariuKiekis = int.Parse(a);
nariai[] narys = new nariai[nariuKiekis];
string[] info = new string[nariuKiekis];
for (int i = 0; i < nariuKiekis; i++)
{
info[i] = failas.ReadLine();
string[] informacija = info[i].Split(' ');
narys[i].vardas = informacija[0];
narys[i].pavarde = informacija[1];
narys[i].eurai = double.Parse(informacija[2]);
narys[i].centai = double.Parse(informacija[3]);
Console.WriteLine("{0} {1} {2} {3}", narys[i].vardas, narys[i].pavarde, narys[i].eurai, narys[i].centai);
}
for (int i = 0; i < nariuKiekis; i++)
{
islaidos = narys[i].eurai * 100 + narys[i].centai;
narys[i].suma = islaidos / 100 * 0.25;
islaidos = narys[i].suma;
Console.WriteLine(narys[i].suma);
surinktiPinigai = surinktiPinigai + islaidos;
}
Console.WriteLine("Surinkti pinigai bendroms išlaidoms: {0} Eurai.", surinktiPinigai);
}
File looks like that:
Command looks like that:
I need to find who has the biggest value in the structure "public double suma" and i need to write first name and last name of it.
What you want is to retrieve from the list the item with the max suma and then you can get it's other properties.
var item = narys.OrderByDescending(i => i.suma).FirstOrDefault();
var name = $"{item?.vardas} {item?.pavarde}";
Notice the use of the ?. operator available since C# 6.0 that verifies item is not null. If by the time you perform this querying you know for sure that collection is not empty then simply:
var item = narys.OrderByDescending(i => i.suma).First();
var name = $"{item.vardas} {item.pavarde}";
You can also use MoreLinq's MaxBy which:
Returns the maximal element of the given sequence, based on the given projection.
You can try using LINQ:
var maxNarys = narys.OrderByDescending(n => n.suma)
.FirstOrDefault();
And then access it's properties like this:
var maxNarvardas = maxNarys.vardas;
EDIT
Also looking at your code more closely:
it seems that you can concat your two loops and add a variables to find max:
var maxSuma = double.MinValue;
var maxIndex = -1;
for (int i = 0; i < nariuKiekis; i++)
{
info[i] = failas.ReadLine();
string[] informacija = info[i].Split(' ');
narys[i].vardas = informacija[0];
narys[i].pavarde = informacija[1];
narys[i].eurai = double.Parse(informacija[2]);
narys[i].centai = double.Parse(informacija[3]);
Console.WriteLine("{0} {1} {2} {3}", narys[i].vardas, narys[i].pavarde, narys[i].eurai, narys[i].centai);
islaidos = narys[i].eurai * 100 + narys[i].centai;
narys[i].suma = islaidos / 100 * 0.25;
islaidos = narys[i].suma;
if(maxSuma < narys[i].suma)
{
maxSuma = narys[i].suma;
maxIndex = i;
}
surinktiPinigai = surinktiPinigai + islaidos;
}
if(maxIndex>=0) Console.WriteLine(narys[maxIndex].suma);

What are the correct SAPI input parameters to the succesfully usage?

I have a problem this COM function I can't know what the correct parameters are.
I get bad notification from VS 2013.
Program: speakBoard
WAVEFORMATEX waveFORMATEX = new WAVEFORMATEX();
waveFORMATEX.wFormatTag = 1;
waveFORMATEX.nChannels = 1;
waveFORMATEX.nSamplesPerSec = 44100;
waveFORMATEX.wBitsPerSample = 16;
waveFORMATEX.nBlockAlign = 4;
waveFORMATEX.cbSize = 0;
SPVTEXTFRAG SPVtextFRAG = new SPVTEXTFRAG();
SPVtextFRAG.pTextStart = "one";
SPVtextFRAG.ulTextLen = 100;
SPVtextFRAG.ulTextSrcOffset = 0;
SpeakBoard1.STTTSEngine se;
Guid rguid = new Guid("ggg");
SpeakBoard1.ISpTTSEngineSite es;
se.Speak(255, ref rguid, ref waveFORMATEX, ref SPVtextFRAG, es);
I face with similar problem for C++. This is my code for filling the main structure:
SPVTEXTFRAG fillSPVTEXTFRAG(){
SPVTEXTFRAG spvTextFrag;
spvTextFrag.pNext = NULL;
spvTextFrag.State.eAction = SPVA_Speak;
spvTextFrag.State.LangID = 3;
spvTextFrag.State.wReserved = 3;
spvTextFrag.State.EmphAdj = 3;
spvTextFrag.State.RateAdj = 3;
spvTextFrag.State.Volume = 100;
spvTextFrag.State.PitchAdj.MiddleAdj = 0;
spvTextFrag.State.PitchAdj.RangeAdj = 0;
spvTextFrag.State.SilenceMSecs = 0;
//spvTextFrag.State.pPhoneIds = ;
spvTextFrag.State.ePartOfSpeech = SPPS_Unknown;// SPPARTOFSPEECH.SPPS_Unknown;
spvTextFrag.State.Context.pCategory;
spvTextFrag.State.Context.pBefore;
spvTextFrag.State.Context.pAfter;
spvTextFrag.pTextStart = L"one";
spvTextFrag.ulTextLen = 100;
spvTextFrag.ulTextSrcOffset = 0;
return spvTextFrag;
}
This code fills one of five parameters for call the Speak method of ISpTTSEngine. But you also need to implement the ISpTTSEngineSite interface for such calls.

Having issue creating recursive constructor

I'm trying to build Quad-tree which receive array of points and split them into 4 cells. those 4 cells(cell1...cell4) are suppose to be created recursively but it doesn't works.
What I'm doing wrong? wasted all day trying fix it.
I erased some basic things not to overload the script here.
class QuadTreeNode
{
private QuadTreeNode cell1;
private QuadTreeNode cell2;
private QuadTreeNode cell3;
private QuadTreeNode cell4;
private int maxppc;
private double leftminX, leftminY, rightmaxX, rightmaxY;
public QuadTreeNode(Point2D leftMin, Point2D rightMax, int maxPPC)
{
this.leftminX = leftMin.East;
this.leftminY = leftMin.North;
this.rightmaxX = rightMax.East;
this.rightmaxY = rightMax.North;
this.maxppc = maxPPC;
}
public QuadTreeNode(Point2D[] pointArray, Point2D leftMin, Point2D rightMax, int maxPPC)
{
for (int i=0; i <4; i++)
{
cellList[i] = new List<Point2D>();
}
allPointList = pointArray.ToList();
this.leftminX = leftMin.East;
this.leftminY = leftMin.North;
this.rightmaxX = rightMax.East;
this.rightmaxY = rightMax.North;
this.maxppc = maxPPC;
if (allPointList.Count > maxPPC)
{
Split(allPointList);
}
}
public void Split(List<Point2D> Array)
{
if (Array.Count > maxppc)
{
double centerE = (this.leftminX + this.rightmaxX) / 2;
double centerN = (this.leftminY + this.rightmaxY) / 2;
double deltaE = (this.rightmaxX - this.leftminX) / 2;
double deltaN = (this.rightmaxY - this.leftminY) / 2;
Point2D Center = new Point2D(centerE, centerN);
this.cell1 = new QuadTreeNode(cellList[0].ToArray(),new Point2D((Center.East - deltaE), (Center.North - deltaN)), Center, maxppc);
this.cell2 = new QuadTreeNode(cellList[1].ToArray(), new Point2D(Center.East, Center.North - deltaN), new Point2D((Center.East + deltaE), Center.North), maxppc);
this.cell3 = new QuadTreeNode(cellList[2].ToArray(), new Point2D((Center.East - deltaE), (Center.North)), new Point2D(Center.East, (Center.North + deltaN)), maxppc);
this.cell4 = new QuadTreeNode(cellList[3].ToArray(), Center, new Point2D((Center.East + deltaE), (Center.North + deltaN)), maxppc);
for (pntIndex = 0; pntIndex < Array.Count; pntIndex++)
{
CellIndex(Array[pntIndex]);
}
pntIndex = 0;
Array.Clear();
for (int c=0; c < 4; c++)
{
Array = cellList[c].ToList();
cellList[0].Clear();
cellList[1].Clear();
cellList[2].Clear();
cellList[3].Clear();
Split(Array);
}
return;
}
else
{
return;
}
}
public void CellIndex(Point2D point)
{
//locates points up to East,North
}
The problem may be with this part:
Array = cellList[c].ToList();
cellList[0].Clear();
cellList[1].Clear();
cellList[2].Clear();
cellList[3].Clear();
Split(Array);
Here, you're copying the list at location c but you're clearing each list at every iteration anyway, so you're likely losing some of your points.

C# - A faster alternative to Convert.ToSingle()

I'm working on a program which reads millions of floating point numbers from a text file. This program runs inside of a game that I'm designing, so I need it to be fast (I'm loading an obj file). So far, loading a relatively small file takes about a minute (without precompilation) because of the slow speed of Convert.ToSingle(). Is there a faster way to do this?
EDIT: Here's the code I use to parse the Obj file
http://pastebin.com/TfgEge9J
using System;
using System.IO;
using System.Collections.Generic;
using OpenTK.Math;
using System.Drawing;
using PlatformLib;
public class ObjMeshLoader
{
public static StreamReader[] LoadMeshes(string fileName)
{
StreamReader mreader = new StreamReader(PlatformLib.Platform.openFile(fileName));
MemoryStream current = null;
List<MemoryStream> mstreams = new List<MemoryStream>();
StreamWriter mwriter = null;
if (!mreader.ReadLine().Contains("#"))
{
mreader.BaseStream.Close();
throw new Exception("Invalid header");
}
while (!mreader.EndOfStream)
{
string cmd = mreader.ReadLine();
string line = cmd;
line = line.Trim(splitCharacters);
line = line.Replace(" ", " ");
string[] parameters = line.Split(splitCharacters);
if (parameters[0] == "mtllib")
{
loadMaterials(parameters[1]);
}
if (parameters[0] == "o")
{
if (mwriter != null)
{
mwriter.Flush();
current.Position = 0;
}
current = new MemoryStream();
mwriter = new StreamWriter(current);
mwriter.WriteLine(parameters[1]);
mstreams.Add(current);
}
else
{
if (mwriter != null)
{
mwriter.WriteLine(cmd);
mwriter.Flush();
}
}
}
mwriter.Flush();
current.Position = 0;
List<StreamReader> readers = new List<StreamReader>();
foreach (MemoryStream e in mstreams)
{
e.Position = 0;
StreamReader sreader = new StreamReader(e);
readers.Add(sreader);
}
return readers.ToArray();
}
public static bool Load(ObjMesh mesh, string fileName)
{
try
{
using (StreamReader streamReader = new StreamReader(Platform.openFile(fileName)))
{
Load(mesh, streamReader);
streamReader.Close();
return true;
}
}
catch { return false; }
}
public static bool Load2(ObjMesh mesh, StreamReader streamReader, ObjMesh prevmesh)
{
if (prevmesh != null)
{
//mesh.Vertices = prevmesh.Vertices;
}
try
{
//streamReader.BaseStream.Position = 0;
Load(mesh, streamReader);
streamReader.Close();
#if DEBUG
Console.WriteLine("Loaded "+mesh.Triangles.Length.ToString()+" triangles and"+mesh.Quads.Length.ToString()+" quadrilaterals parsed, with a grand total of "+mesh.Vertices.Length.ToString()+" vertices.");
#endif
return true;
}
catch (Exception er) { Console.WriteLine(er); return false; }
}
static char[] splitCharacters = new char[] { ' ' };
static List<Vector3> vertices;
static List<Vector3> normals;
static List<Vector2> texCoords;
static Dictionary<ObjMesh.ObjVertex, int> objVerticesIndexDictionary;
static List<ObjMesh.ObjVertex> objVertices;
static List<ObjMesh.ObjTriangle> objTriangles;
static List<ObjMesh.ObjQuad> objQuads;
static Dictionary<string, Bitmap> materials = new Dictionary<string, Bitmap>();
static void loadMaterials(string path)
{
StreamReader mreader = new StreamReader(Platform.openFile(path));
string current = "";
bool isfound = false;
while (!mreader.EndOfStream)
{
string line = mreader.ReadLine();
line = line.Trim(splitCharacters);
line = line.Replace(" ", " ");
string[] parameters = line.Split(splitCharacters);
if (parameters[0] == "newmtl")
{
if (materials.ContainsKey(parameters[1]))
{
isfound = true;
}
else
{
current = parameters[1];
}
}
if (parameters[0] == "map_Kd")
{
if (!isfound)
{
string filename = "";
for (int i = 1; i < parameters.Length; i++)
{
filename += parameters[i];
}
string searcher = "\\" + "\\";
filename.Replace(searcher, "\\");
Bitmap mymap = new Bitmap(filename);
materials.Add(current, mymap);
isfound = false;
}
}
}
}
static float parsefloat(string val)
{
return Convert.ToSingle(val);
}
int remaining = 0;
static string GetLine(string text, ref int pos)
{
string retval = text.Substring(pos, text.IndexOf(Environment.NewLine, pos));
pos = text.IndexOf(Environment.NewLine, pos);
return retval;
}
static void Load(ObjMesh mesh, StreamReader textReader)
{
//try {
//vertices = null;
//objVertices = null;
if (vertices == null)
{
vertices = new List<Vector3>();
}
if (normals == null)
{
normals = new List<Vector3>();
}
if (texCoords == null)
{
texCoords = new List<Vector2>();
}
if (objVerticesIndexDictionary == null)
{
objVerticesIndexDictionary = new Dictionary<ObjMesh.ObjVertex, int>();
}
if (objVertices == null)
{
objVertices = new List<ObjMesh.ObjVertex>();
}
objTriangles = new List<ObjMesh.ObjTriangle>();
objQuads = new List<ObjMesh.ObjQuad>();
mesh.vertexPositionOffset = vertices.Count;
string line;
string alltext = textReader.ReadToEnd();
int pos = 0;
while ((line = GetLine(alltext, pos)) != null)
{
if (line.Length < 2)
{
break;
}
//line = line.Trim(splitCharacters);
//line = line.Replace(" ", " ");
string[] parameters = line.Split(splitCharacters);
switch (parameters[0])
{
case "usemtl":
//Material specification
try
{
mesh.Material = materials[parameters[1]];
}
catch (KeyNotFoundException)
{
Console.WriteLine("WARNING: Texture parse failure: " + parameters[1]);
}
break;
case "p": // Point
break;
case "v": // Vertex
float x = parsefloat(parameters[1]);
float y = parsefloat(parameters[2]);
float z = parsefloat(parameters[3]);
vertices.Add(new Vector3(x, y, z));
break;
case "vt": // TexCoord
float u = parsefloat(parameters[1]);
float v = parsefloat(parameters[2]);
texCoords.Add(new Vector2(u, v));
break;
case "vn": // Normal
float nx = parsefloat(parameters[1]);
float ny = parsefloat(parameters[2]);
float nz = parsefloat(parameters[3]);
normals.Add(new Vector3(nx, ny, nz));
break;
case "f":
switch (parameters.Length)
{
case 4:
ObjMesh.ObjTriangle objTriangle = new ObjMesh.ObjTriangle();
objTriangle.Index0 = ParseFaceParameter(parameters[1]);
objTriangle.Index1 = ParseFaceParameter(parameters[2]);
objTriangle.Index2 = ParseFaceParameter(parameters[3]);
objTriangles.Add(objTriangle);
break;
case 5:
ObjMesh.ObjQuad objQuad = new ObjMesh.ObjQuad();
objQuad.Index0 = ParseFaceParameter(parameters[1]);
objQuad.Index1 = ParseFaceParameter(parameters[2]);
objQuad.Index2 = ParseFaceParameter(parameters[3]);
objQuad.Index3 = ParseFaceParameter(parameters[4]);
objQuads.Add(objQuad);
break;
}
break;
}
}
//}catch(Exception er) {
// Console.WriteLine(er);
// Console.WriteLine("Successfully recovered. Bounds/Collision checking may fail though");
//}
mesh.Vertices = objVertices.ToArray();
mesh.Triangles = objTriangles.ToArray();
mesh.Quads = objQuads.ToArray();
textReader.BaseStream.Close();
}
public static void Clear()
{
objVerticesIndexDictionary = null;
vertices = null;
normals = null;
texCoords = null;
objVertices = null;
objTriangles = null;
objQuads = null;
}
static char[] faceParamaterSplitter = new char[] { '/' };
static int ParseFaceParameter(string faceParameter)
{
Vector3 vertex = new Vector3();
Vector2 texCoord = new Vector2();
Vector3 normal = new Vector3();
string[] parameters = faceParameter.Split(faceParamaterSplitter);
int vertexIndex = Convert.ToInt32(parameters[0]);
if (vertexIndex < 0) vertexIndex = vertices.Count + vertexIndex;
else vertexIndex = vertexIndex - 1;
//Hmm. This seems to be broken.
try
{
vertex = vertices[vertexIndex];
}
catch (Exception)
{
throw new Exception("Vertex recognition failure at " + vertexIndex.ToString());
}
if (parameters.Length > 1)
{
int texCoordIndex = Convert.ToInt32(parameters[1]);
if (texCoordIndex < 0) texCoordIndex = texCoords.Count + texCoordIndex;
else texCoordIndex = texCoordIndex - 1;
try
{
texCoord = texCoords[texCoordIndex];
}
catch (Exception)
{
Console.WriteLine("ERR: Vertex " + vertexIndex + " not found. ");
throw new DllNotFoundException(vertexIndex.ToString());
}
}
if (parameters.Length > 2)
{
int normalIndex = Convert.ToInt32(parameters[2]);
if (normalIndex < 0) normalIndex = normals.Count + normalIndex;
else normalIndex = normalIndex - 1;
normal = normals[normalIndex];
}
return FindOrAddObjVertex(ref vertex, ref texCoord, ref normal);
}
static int FindOrAddObjVertex(ref Vector3 vertex, ref Vector2 texCoord, ref Vector3 normal)
{
ObjMesh.ObjVertex newObjVertex = new ObjMesh.ObjVertex();
newObjVertex.Vertex = vertex;
newObjVertex.TexCoord = texCoord;
newObjVertex.Normal = normal;
int index;
if (objVerticesIndexDictionary.TryGetValue(newObjVertex, out index))
{
return index;
}
else
{
objVertices.Add(newObjVertex);
objVerticesIndexDictionary[newObjVertex] = objVertices.Count - 1;
return objVertices.Count - 1;
}
}
}
Based on your description and the code you've posted, I'm going to bet that your problem isn't with the reading, the parsing, or the way you're adding things to your collections. The most likely problem is that your ObjMesh.Objvertex structure doesn't override GetHashCode. (I'm assuming that you're using code similar to http://www.opentk.com/files/ObjMesh.cs.
If you're not overriding GetHashCode, then your objVerticesIndexDictionary is going to perform very much like a linear list. That would account for the performance problem that you're experiencing.
I suggest that you look into providing a good GetHashCode method for your ObjMesh.Objvertex class.
See Why is ValueType.GetHashCode() implemented like it is? for information about the default GetHashCode implementation for value types and why it's not suitable for use in a hash table or dictionary.
Edit 3: The problem is NOT with the parsing.
It's with how you read the file. If you read it properly, it would be faster; however, it seems like your reading is unusually slow. My original suspicion was that it was because of excess allocations, but it seems like there might be other problems with your code too, since that doesn't explain the entire slowdown.
Nevertheless, here's a piece of code I made that completely avoids all object allocations:
static void Main(string[] args)
{
long counter = 0;
var sw = Stopwatch.StartNew();
var sb = new StringBuilder();
var text = File.ReadAllText("spacestation.obj");
for (int i = 0; i < text.Length; i++)
{
int start = i;
while (i < text.Length &&
(char.IsDigit(text[i]) || text[i] == '-' || text[i] == '.'))
{ i++; }
if (i > start)
{
sb.Append(text, start, i - start); //Copy data to the buffer
float value = Parse(sb); //Parse the data
sb.Remove(0, sb.Length); //Clear the buffer
counter++;
}
}
sw.Stop();
Console.WriteLine("{0:N0}", sw.Elapsed.TotalSeconds); //Only a few ms
}
with this parser:
const int MIN_POW_10 = -16, int MAX_POW_10 = 16,
NUM_POWS_10 = MAX_POW_10 - MIN_POW_10 + 1;
static readonly float[] pow10 = GenerateLookupTable();
static float[] GenerateLookupTable()
{
var result = new float[(-MIN_POW_10 + MAX_POW_10) * 10];
for (int i = 0; i < result.Length; i++)
result[i] = (float)((i / NUM_POWS_10) *
Math.Pow(10, i % NUM_POWS_10 + MIN_POW_10));
return result;
}
static float Parse(StringBuilder str)
{
float result = 0;
bool negate = false;
int len = str.Length;
int decimalIndex = str.Length;
for (int i = len - 1; i >= 0; i--)
if (str[i] == '.')
{ decimalIndex = i; break; }
int offset = -MIN_POW_10 + decimalIndex;
for (int i = 0; i < decimalIndex; i++)
if (i != decimalIndex && str[i] != '-')
result += pow10[(str[i] - '0') * NUM_POWS_10 + offset - i - 1];
else if (str[i] == '-')
negate = true;
for (int i = decimalIndex + 1; i < len; i++)
if (i != decimalIndex)
result += pow10[(str[i] - '0') * NUM_POWS_10 + offset - i];
if (negate)
result = -result;
return result;
}
it happens in a small fraction of a second.
Of course, this parser is poorly tested and has these current restrictions (and more):
Don't try parsing more digits (decimal and whole) than provided for in the array.
No error handling whatsoever.
Only parses decimals, not exponents! i.e. it can parse 1234.56 but not 1.23456E3.
Doesn't care about globalization/localization. Your file is only in a single format, so there's no point caring about that kind of stuff because you're probably using English to store it anyway.
It seems like you won't necessarily need this much overkill, but take a look at your code and try to figure out the bottleneck. It seems to be neither the reading nor the parsing.
Have you measured that the speed problem is really caused by Convert.ToSingle?
In the code you included, I see you create lists and dictionaries like this:
normals = new List<Vector3>();
texCoords = new List<Vector2>();
objVerticesIndexDictionary = new Dictionary<ObjMesh.ObjVertex, int>();
And then when you read the file, you add in the collection one item at a time.
One of the possible optimizations would be to save total number of normals, texCoords, indexes and everything at the start of the file, and then initialize these collections by these numbers. This will pre-allocate the buffers used by collections, so adding items to the them will be pretty fast.
So the collection creation should look like this:
// These values should be stored at the beginning of the file
int totalNormals = Convert.ToInt32(textReader.ReadLine());
int totalTexCoords = Convert.ToInt32(textReader.ReadLine());
int totalIndexes = Convert.ToInt32(textReader.ReadLine());
normals = new List<Vector3>(totalNormals);
texCoords = new List<Vector2>(totalTexCoords);
objVerticesIndexDictionary = new Dictionary<ObjMesh.ObjVertex, int>(totalIndexes);
See List<T> Constructor (Int32) and Dictionary<TKey, TValue> Constructor (Int32).
This related question is for C++, but is definitely worth a read.
For reading as fast as possible, you're probably going to want to map the file into memory and then parse using some custom floating point parser, especially if you know the numbers are always in a specific format (i.e. you're the one generating the input files in the first place).
I tested .Net string parsing once and the fastest function to parse text was the old VB Val() function. You could pull the relevant parts out of Microsoft.VisualBasic.Conversion Val(string)
Converting String to numbers
Comparison of relative test times (ms / 100000 conversions)
Double Single Integer Int(w/ decimal point)
14 13 6 16 Val(Str)
14 14 6 16 Cxx(Val(Str)) e.g., CSng(Val(str))
22 21 17 e! Convert.To(str)
23 21 16 e! XX.Parse(str) e.g. Single.Parse()
30 31 31 32 Cxx(str)
Val: fastest, part of VisualBasic dll, skips non-numeric,
ConvertTo and Parse: slower, part of core, exception on bad format (including decimal point)
Cxx: slowest (for strings), part of core, consistent times across formats

Auto Generate alphanumeric Unique Id with C#

Total string length is 5 chars
I have a scenario, ID starts with
A0001 and ends with A9999 then
B0001 to B9999 until F0001 to f9999
after that
FA001 to FA999 then
FB001 to FB999 until ....FFFF9
Please suggest any idea on how to create this format.
public static IEnumerable<string> Numbers()
{
return Enumerable.Range(0xA0000, 0xFFFF9 - 0xA0000 + 1)
.Select(x => x.ToString("X"));
}
You could also have an id generator class:
public class IdGenerator
{
private const int Min = 0xA0000;
private const int Max = 0xFFFF9;
private int _value = Min - 1;
public string NextId()
{
if (_value < Max)
{
_value++;
}
else
{
_value = Min;
}
return _value.ToString("X");
}
}
I am a few years late. But I hope my answer will help everyone looking for a good ID Generator. None of the previous answers work as expected and do not answer this question.
My answer fits the requirements perfectly. And more!!!
Notice that setting the _fixedLength to ZERO will create dynamically sized ID's.
Setting it to anything else will create FIXED LENGTH ID's;
Notice also that calling the overload that takes a current ID will "seed" the class and consecutive calls DO NOT need to be called with another ID. Unless you had random ID's and need the next one on each.
Enjoy!
public static class IDGenerator
{
private static readonly char _minChar = 'A';
private static readonly char _maxChar = 'C';
private static readonly int _minDigit = 1;
private static readonly int _maxDigit = 5;
private static int _fixedLength = 5;//zero means variable length
private static int _currentDigit = 1;
private static string _currentBase = "A";
public static string NextID()
{
if(_currentBase[_currentBase.Length - 1] <= _maxChar)
{
if(_currentDigit <= _maxDigit)
{
var result = string.Empty;
if(_fixedLength > 0)
{
var prefixZeroCount = _fixedLength - _currentBase.Length;
if(prefixZeroCount < _currentDigit.ToString().Length)
throw new InvalidOperationException("The maximum length possible has been exeeded.");
result = result = _currentBase + _currentDigit.ToString("D" + prefixZeroCount.ToString());
}
else
{
result = _currentBase + _currentDigit.ToString();
}
_currentDigit++;
return result;
}
else
{
_currentDigit = _minDigit;
if(_currentBase[_currentBase.Length - 1] == _maxChar)
{
_currentBase = _currentBase.Remove(_currentBase.Length - 1) + _minChar;
_currentBase += _minChar.ToString();
}
else
{
var newChar = _currentBase[_currentBase.Length - 1];
newChar++;
_currentBase = _currentBase.Remove(_currentBase.Length - 1) + newChar.ToString();
}
return NextID();
}
}
else
{
_currentDigit = _minDigit;
_currentBase += _minChar.ToString();
return NextID();
}
}
public static string NextID(string currentId)
{
if(string.IsNullOrWhiteSpace(currentId))
return NextID();
var charCount = currentId.Length;
var indexFound = -1;
for(int i = 0; i < charCount; i++)
{
if(!char.IsNumber(currentId[i]))
continue;
indexFound = i;
break;
}
if(indexFound > -1)
{
_currentBase = currentId.Substring(0, indexFound);
_currentDigit = int.Parse(currentId.Substring(indexFound)) + 1;
}
return NextID();
}
}
This is a sample of the ouput using _fixedLength = 4 and _maxDigit = 5
A001
A002
A003
A004
A005
B001
B002
B003
B004
B005
C001
C002
C003
C004
C005
AA01
AA02
AA03
AA04
AA05
AB01
AB02
AB03
AB04
AB05
AC01
AC02
AC03
AC04
AC05
see this code
private void button1_Click(object sender, EventArgs e)
{
string get = label1.Text.Substring(7); //label1.text=ATHCUS-100
MessageBox.Show(get);
string ou="ATHCUS-"+(Convert.ToInt32(get)+1).ToString();
label1.Text = ou.ToString();
}
Run this query in order to get the last ID in the database
SELECT TOP 1 [ID_COLUMN] FROM [NAME_OF_TABLE] ORDER BY [ID_COLUMN] DESC
Read the result to a variable and then run the following function on the result in order to get the next ID.
public string NextID(string lastID)
{
var allLetters = new string[] {"A", "B", "C", "D", "E", "F"};
var lastLetter = lastID.Substring(0, 1);
var lastNumber = int.Parse(lastID.Substring(1));
if (Array.IndexOf(allLetters, lastLetter) < allLetters.Length - 1 &&
lastNumber == 9999)
{
//increase the letter
lastLetter = allLetters(Array.IndexOf(allLetters, lastLetter) + 1);
lastNumber = 0;
} else {
lastLetter = "!";
}
var result = lastLetter + (lastNumber + 1).ToString("0000");
//ensure we haven't exceeded the upper limit
if (result.SubString(0, 1) == "!") {
result = "Upper Bounds Exceeded!";
}
return result;
}
DISCLAIMER
This code will only generate the first set of IDs. I do not understand the process of generating the second set.
If you need to take it from the database and do this you can use something like the following.
int dbid = /* get id from db */
string id = dbid.ToString("X5");
This should give you the format you are looking for as a direct convert from the DB ID.

Categories