Customer Dictionary Index [duplicate] - c#

This question already has answers here:
What is an IndexOutOfRangeException / ArgumentOutOfRangeException and how do I fix it?
(5 answers)
Closed 6 years ago.
I have a class named ClusterMember as:
public class ClusterMember
{
public string _name;
public ClusterMember(string _name)
{
this._name = _name;
}
public string _Name
{
get { return _name; }
set { _name = value; }
}
}
public class Cluster
{
private Dictionary<int, List<ClusterMember>> _dic;
public Cluster(Dictionary<int, List<ClusterMember>> _dic)
{
this._dic = _dic;
}
public Dictionary<int, List<ClusterMember>> _Dictionary
{
get { return _dic; }
set { _dic = value; }
}
// adding members to clusters
public void AddToCluster(int _id, ClusterMember _clusMem)
{
// checks if cluster with specific id is already in Dictionary
if (!_dic.ContainsKey(_id))
{
_dic.Add(_id, new List<ClusterMember>());
}
else
{
_dic[_id].Add(_clusMem);
}
}
// get members count for specific cluster id
public int GetCount(int id)
{
return _dic[id].Count;
}
// get members count for all clusters
public Dictionary<int, int> GetCounts()
{
return _dic.ToDictionary(k => k.Key, v => v.Value.Count);
}
public void Print_Clusters(List<Cluster> _clusterToPrint, double _alpha, int _length)
{
Console.WriteLine("\n" + "Number of Customers = " + _length + "\n");
Console.WriteLine("\n" + "Alpha = " + _alpha + "\n");
Console.WriteLine("\n" + "Number of Clusters = " + _clusterToPrint.Max() + "\n");
foreach ( var _clusters in _clusterToPrint )
{
Console.WriteLine("Cluster ID {0} - ClusterMember {1}", _clusters._Dictionary.Keys, _clusters._Dictionary.Values);
Console.Write("\n");
}
Console.ReadLine();
}
}
When I use these classes in this method as:
public static void DP_Cluster(List<string> _cust, double _alpha)
{
var _customer = new List<string>();
var _currentTables = 0; // current number of tables i.e. "k"
var _dicInitial = new Dictionary<int, List<ClusterMember>>();
var _customerNumber = 0; // running customer number i.e. "n"
var _probOld = new Dictionary<int, double>();
//var _probOld = new List<Double>(); // porbability to be in Old cluster
var _probNew = 0.0; // porbability to be in New cluster
List<Cluster> _myClusters = new List<Cluster>();
Cluster _cluster = new Cluster(_dicInitial);
// add first customer from "_cust" list directly to a new cluster
_cluster.AddToCluster(++_currentTables, new ClusterMember(_cust.ElementAt(_customerNumber)));
_myClusters.Add(_cluster);
_probOld.Add(_currentTables, Convert.ToDouble(1) / Convert.ToDouble(1 + _alpha));
for (int _i = 1; _i < _cust.Count - 1; _i++)
{
if (_i <= _currentTables)
{
// get customer Count in Cluster i / customerNumber + alpha
// Got ERROR here at "_myClusters[_i]"
double _probOldValue = _myClusters[_i].GetCount(_i) / ((_i + 1) - 1 + _alpha);
_probOld.Add(_currentTables, _probOldValue);
}
else if ( _i == _currentTables + 1)
{
_probNew =_alpha / ((_i + 1) - 1 + _alpha);
_currentTables++;
_probOld.Add(_currentTables, _probNew);
}
List<int> _keyList = new List<int>(_probOld.Keys);
Random _random = new Random();
int _randomKey = _keyList[_random.Next(_keyList.Count)];
_cluster.AddToCluster(_randomKey, new ClusterMember(_cust.ElementAt(_i)));
}
_myClusters.Add(_cluster);
_cluster.Print_Clusters(_myClusters, _alpha, _cust.Count);
}
public static List<string> GetRandomString(int _numOfStrings, int _stringLength)
{
string[] _arrStr = new string[_numOfStrings];
List<string> _listSt;
const string _chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";
var _random = new Random();
for (int _i = 0; _i < _arrStr.Length; _i++)
{
_arrStr[_i] = new string(Enumerable.Repeat(_chars, _stringLength).Select(s => s[_random.Next(s.Length)]).ToArray());
}
_listSt = new List<string>(_arrStr);
return _listSt;
}
static int Main()
{
double _alfa = 5;
int _n = 30;
List<string> _data = GetRandomString(_n, 8);
DP_Cluster(_data, _alfa);
return 0;
}
The ERROR is:
Index was out of range. Must be non-negative and less than the size of the collection.
whereas I have added ++_currentTables in _cluster i.e. object of class Cluster here it should be 1 which is not out of range.
I'm wanting to take the Count at specific cluster id which has been added already in List whereas the error is demanding less than size of index value. I think the value which I have inserted at this line:
_cluster.AddToCluster(++_currentTables, new ClusterMember(_cust.ElementAt(_customerNumber)));
I have inserted 1 i.e. (_++currentTables) as first index of _dic member of class i.e. Cluster whereas by default it should start with 0.
Is this an error of index insertion? But I want to start the cluster number with 1 not with 0. How to sort out this error?

Blindly running code throws exception at this line:
_myCluster.Count is 1, means you can only access _myCluster[0]
Value of _i is 1, so you are trying to access _myCluster[1], therefore exception.
Error is probably that what you start _i from 1 (indexes are zero-based), perhaps you want to access _myCluster[i - 1], only you know.

Related

Importing and removing duplicates from a massive amount of text files using C# and Redis

This is a bit of a doozy and it's been a while since I worked with C#, so bear with me:
I'm running a jruby script to iterate through 900 files (5 Mb - 1500 Mb in size) to figure out how many dupes STILL exist within these (already uniq'd) files. I had little luck with awk.
My latest idea was to insert them into a local MongoDB instance like so:
db.collection('hashes').update({ :_id => hash}, { $inc: { count: 1} }, { upsert: true)
... so that later I could just query it like db.collection.where({ count: { $gt: 1 } }) to get all the dupes.
This is working great except it's been over 24 hours and at the time of writing I'm at 72,532,927 Mongo entries and growing.
I think Ruby's .each_line is bottlnecking the IO hardcore:
So what I'm thinking now is compiling a C# program which fires up a thread PER EACH FILE and inserts the line (md5 hash) into a Redis list.
From there, I could have another compiled C# program simply pop the values off and ignore the save if the count is 1.
So the questions are:
Will using a compiled file reader and multithreading the file reads significantly improve performance?
Is using Redis even necessary? With a tremendous amount of AWS memory, could I not just use the threads to fill some sort of a list atomically and proceed from there?
Thanks in advance.
Updated
New solution. Old solution. The main idea is to calculate dummy hashes(just sum of all chars in string) of each line and store it in Dictionary<ulong, List<LinePosition>> _hash2LinePositions. It's possible to have multiple hashes in the same stream and it solves by List in Dictionary Value. When the hashes are the same, we read and compare the strings from the streams. LinePosition is using for storing info about line - position in stream and its length. I don't have such huge files as you, but my tests shows that it works. Here is the full code:
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
public class Solution
{
struct LinePosition
{
public long Start;
public long Length;
public LinePosition(long start, long count)
{
Start = start;
Length = count;
}
public override string ToString()
{
return string.Format("Start: {0}, Length: {1}", Start, Length);
}
}
class TextFileHasher : IDisposable
{
readonly Dictionary<ulong, List<LinePosition>> _hash2LinePositions;
readonly Stream _stream;
bool _isDisposed;
public HashSet<ulong> Hashes { get; private set; }
public string Name { get; private set; }
public TextFileHasher(string name, Stream stream)
{
Name = name;
_stream = stream;
_hash2LinePositions = new Dictionary<ulong, List<LinePosition>>();
Hashes = new HashSet<ulong>();
}
public override string ToString()
{
return Name;
}
public void CalculateFileHash()
{
int readByte = -1;
ulong dummyLineHash = 0;
// Line start position in file
long startPosition = 0;
while ((readByte = _stream.ReadByte()) != -1) {
// Read until new line
if (readByte == '\r' || readByte == '\n') {
// If there was data
if (dummyLineHash != 0) {
// Add line hash and line position to the dict
AddToDictAndHash(dummyLineHash, startPosition, _stream.Position - 1 - startPosition);
// Reset line hash
dummyLineHash = 0;
}
}
else {
// Was it new line ?
if (dummyLineHash == 0)
startPosition = _stream.Position - 1;
// Calculate dummy hash
dummyLineHash += (uint)readByte;
}
}
if (dummyLineHash != 0) {
// Add line hash and line position to the dict
AddToDictAndHash(dummyLineHash, startPosition, _stream.Position - startPosition);
// Reset line hash
dummyLineHash = 0;
}
}
public List<LinePosition> GetLinePositions(ulong hash)
{
return _hash2LinePositions[hash];
}
public List<string> GetDuplicates()
{
List<string> duplicates = new List<string>();
foreach (var key in _hash2LinePositions.Keys) {
List<LinePosition> linesPos = _hash2LinePositions[key];
if (linesPos.Count > 1) {
duplicates.AddRange(FindExactDuplicates(linesPos));
}
}
return duplicates;
}
public void Dispose()
{
if (_isDisposed)
return;
_stream.Dispose();
_isDisposed = true;
}
private void AddToDictAndHash(ulong hash, long start, long count)
{
List<LinePosition> linesPosition;
if (!_hash2LinePositions.TryGetValue(hash, out linesPosition)) {
linesPosition = new List<LinePosition>() { new LinePosition(start, count) };
_hash2LinePositions.Add(hash, linesPosition);
}
else {
linesPosition.Add(new LinePosition(start, count));
}
Hashes.Add(hash);
}
public byte[] GetLineAsByteArray(LinePosition prevPos)
{
long len = prevPos.Length;
byte[] lineBytes = new byte[len];
_stream.Seek(prevPos.Start, SeekOrigin.Begin);
_stream.Read(lineBytes, 0, (int)len);
return lineBytes;
}
private List<string> FindExactDuplicates(List<LinePosition> linesPos)
{
List<string> duplicates = new List<string>();
linesPos.Sort((x, y) => x.Length.CompareTo(y.Length));
LinePosition prevPos = linesPos[0];
for (int i = 1; i < linesPos.Count; i++) {
if (prevPos.Length == linesPos[i].Length) {
var prevLineArray = GetLineAsByteArray(prevPos);
var thisLineArray = GetLineAsByteArray(linesPos[i]);
if (prevLineArray.SequenceEqual(thisLineArray)) {
var line = System.Text.Encoding.Default.GetString(prevLineArray);
duplicates.Add(line);
}
#if false
string prevLine = System.Text.Encoding.Default.GetString(prevLineArray);
string thisLine = System.Text.Encoding.Default.GetString(thisLineArray);
Console.WriteLine("PrevLine: {0}\r\nThisLine: {1}", prevLine, thisLine);
StringBuilder sb = new StringBuilder();
sb.Append(prevPos);
sb.Append(" is '");
sb.Append(prevLine);
sb.Append("'. ");
sb.AppendLine();
sb.Append(linesPos[i]);
sb.Append(" is '");
sb.Append(thisLine);
sb.AppendLine("'. ");
sb.Append("Equals => ");
sb.Append(prevLine.CompareTo(thisLine) == 0);
Console.WriteLine(sb.ToString());
#endif
}
else {
prevPos = linesPos[i];
}
}
return duplicates;
}
}
public static void Main(String[] args)
{
List<TextFileHasher> textFileHashers = new List<TextFileHasher>();
string text1 = "abc\r\ncba\r\nabc";
TextFileHasher tfh1 = new TextFileHasher("Text1", new MemoryStream(System.Text.Encoding.Default.GetBytes(text1)));
tfh1.CalculateFileHash();
textFileHashers.Add(tfh1);
string text2 = "def\r\ncba\r\nwet";
TextFileHasher tfh2 = new TextFileHasher("Text2", new MemoryStream(System.Text.Encoding.Default.GetBytes(text2)));
tfh2.CalculateFileHash();
textFileHashers.Add(tfh2);
string text3 = "def\r\nbla\r\nwat";
TextFileHasher tfh3 = new TextFileHasher("Text3", new MemoryStream(System.Text.Encoding.Default.GetBytes(text3)));
tfh3.CalculateFileHash();
textFileHashers.Add(tfh3);
List<string> totalDuplicates = new List<string>();
Dictionary<ulong, Dictionary<TextFileHasher, List<LinePosition>>> totalHashes = new Dictionary<ulong, Dictionary<TextFileHasher, List<LinePosition>>>();
textFileHashers.ForEach(tfh => {
foreach(var dummyHash in tfh.Hashes) {
Dictionary<TextFileHasher, List<LinePosition>> tfh2LinePositions = null;
if (!totalHashes.TryGetValue(dummyHash, out tfh2LinePositions))
totalHashes[dummyHash] = new Dictionary<TextFileHasher, List<LinePosition>>() { { tfh, tfh.GetLinePositions(dummyHash) } };
else {
List<LinePosition> linePositions = null;
if (!tfh2LinePositions.TryGetValue(tfh, out linePositions))
tfh2LinePositions[tfh] = tfh.GetLinePositions(dummyHash);
else
linePositions.AddRange(tfh.GetLinePositions(dummyHash));
}
}
});
HashSet<TextFileHasher> alreadyGotDuplicates = new HashSet<TextFileHasher>();
foreach(var hash in totalHashes.Keys) {
var tfh2LinePositions = totalHashes[hash];
var tfh = tfh2LinePositions.Keys.FirstOrDefault();
// Get duplicates in the TextFileHasher itself
if (tfh != null && !alreadyGotDuplicates.Contains(tfh)) {
totalDuplicates.AddRange(tfh.GetDuplicates());
alreadyGotDuplicates.Add(tfh);
}
if (tfh2LinePositions.Count <= 1) {
continue;
}
// Algo to get duplicates in more than 1 TextFileHashers
var tfhs = tfh2LinePositions.Keys.ToArray();
for (int i = 0; i < tfhs.Length; i++) {
var tfh1Positions = tfhs[i].GetLinePositions(hash);
for (int j = i + 1; j < tfhs.Length; j++) {
var tfh2Positions = tfhs[j].GetLinePositions(hash);
for (int k = 0; k < tfh1Positions.Count; k++) {
var tfh1Pos = tfh1Positions[k];
var tfh1ByteArray = tfhs[i].GetLineAsByteArray(tfh1Pos);
for (int m = 0; m < tfh2Positions.Count; m++) {
var tfh2Pos = tfh2Positions[m];
if (tfh1Pos.Length != tfh2Pos.Length)
continue;
var tfh2ByteArray = tfhs[j].GetLineAsByteArray(tfh2Pos);
if (tfh1ByteArray.SequenceEqual(tfh2ByteArray)) {
var line = System.Text.Encoding.Default.GetString(tfh1ByteArray);
totalDuplicates.Add(line);
}
}
}
}
}
}
Console.WriteLine();
if (totalDuplicates.Count > 0) {
Console.WriteLine("Total number of duplicates: {0}", totalDuplicates.Count);
Console.WriteLine("#######################");
totalDuplicates.ForEach(x => Console.WriteLine("{0}", x));
Console.WriteLine("#######################");
}
// Free resources
foreach (var tfh in textFileHashers)
tfh.Dispose();
}
}
If you have tons of ram... You guys are overthinking it...
var fileLines = File.ReadAllLines(#"c:\file.csv").Distinct();

Failing to sort an Array containing objects. C#

I am working on a school project and I have spent 5 hours trying to understand how to go about sorting an Array with an object containing four dimensions. What I set out to do was to sort them by productCode or drinkName. When I read assorted threads people tell OP to use LINQ. I am not supposed to use that and, I get more and more confused as what method to use. I am told by the teacher, to use bubble sort(bad algorithm, I know) and I do that all fine on an Array containing one dimension. I resorted to try Array.Sort but then I get System.InvalidOperationException.
I am going insane and I am stuck even though I read multiple threads on the subject. I might be using ToString in the wrong manner. Any nudge would be appreciated.
class soda
{
string drinkName;
string drinkType;
int drinkPrice;
int productCode;
//Construct for the beverage
public soda(string _drinkName, string _drinkType, int _drinkPrice, int _productCode)
{
drinkName = _drinkName;
drinkType = _drinkType;
drinkPrice = _drinkPrice;
productCode = _productCode;
}
//Property for the drink name e.g. Coca Cola, Ramlösa or Pripps lättöl
public string Drink_name()
{
return drinkName;
//set { drinkName = value; }
}
//Property for the drink type e.g. Soda, fizzy water or beer
public string Drink_type()
{
return drinkType;
//set { drinkType = value; }
}
//Property for the drink price in SEK
public int Drink_price()
{
return drinkPrice;
//set { drinkPrice = value; }
}
//Property for the product code e.g. 1, 2 or ...
public int Product_code()
{
return productCode;
//set { productCode = value; }
}
//Property for the product code e.g. 1, 2 or ...
public int _Product_code
{
get { return productCode; }
set { productCode = value; }
}
public override string ToString()
{
return string.Format(drinkName + " " + drinkType + " " + drinkPrice + " " + productCode);
//return string.Format("The beverage {0} is of the type {1} and costs {2} SEK.", drinkName, drinkType, drinkPrice, productCode);
}
}
class Sodacrate
{
private soda[] bottles; //Crate the array bottles from the class soda.
private int antal_flaskor = 0; //Keeps tracks on the amount of bottles. 25 is the maximum allowed.
//Construct
public Sodacrate()
{
bottles = new soda[25];
}
public void sort_sodas()
{
string drinkName = "";
int drinkPrice = 0;
int productCode = 0;
Array.Sort(bottles, delegate (soda bottle1, soda bottle2) { return bottle1._Product_code.CompareTo(bottle2._Product_code); });
foreach (var beverage in bottles)
{
if (beverage != null)
{
drinkName = beverage.Drink_name(); drinkPrice = beverage.Drink_price(); productCode = beverage.Product_code();
Console.Write(drinkName + " " + drinkPrice + " " + productCode);
}
}
}
}
----------------------edit---------------
Thanks for the help I am getting closer to my solution and have to thursday lunch on me to solve my problems.
Still I have problem with my sort;
//Exception error When I try to have .Product_Name the compiler protests. Invalid token
public void sort_Sodas()
{
int max = bottles.Length;
//Outer loop for complete [bottles]
for (int i = 1; i < max; i++)
{
//Inner loop for row by row
int nrLeft = max - i;
for (int j = 0; j < (max - i); j++)
{
if (bottles[j].Product_code > bottles[j + 1].Product_code)
{
int temp = bottles[j].Product_code;
bottles[j] = bottles[j + 1];
bottles[j + 1].Product_code = temp;
}
}
}
}
Also my Linear search only returns one vallue when I want all those that are true to the product group. I tried a few different things in the Run() for faster experimentation. I will append the current code.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
namespace Sodacrate
{
//Soda - contains the properties for the bottles that go in to the crate
class Soda : IComparable<Soda>
{
string drinkName;
string drinkType;
int drinkPrice;
int productCode;
//Construct for the beverage
public Soda(string _drinkName, string _drinkType, int _drinkPrice, int _productCode)
{
drinkName = _drinkName;
drinkType = _drinkType;
drinkPrice = _drinkPrice;
productCode = _productCode;
}
//Property for the drink name e.g. Coca Cola, Ramlösa or Pripps lättöl
public string Drink_name
{
get { return drinkName; }
set { drinkName = value; }
}
//Property for the drink type e.g. Soda, fizzy water or beer
public string Drink_type
{
get { return drinkType; }
set { drinkType = value; }
}
//Property for the drink price in SEK
public int Drink_price
{
get { return drinkPrice; }
set { drinkPrice = value; }
}
//Property for the product code e.g. 1, 2 or ...
public int Product_code
{
get { return productCode; }
set { productCode = value; }
}
//Override for ToString to get text instead of info about the object
public override string ToString()
{
return string.Format("{0,0} Type {1,-16} Price {2,-10} Code {3, -5} ", drinkName, drinkType, drinkPrice, productCode);
}
//Compare to solve my issues with sorting
public int CompareTo(Soda other)
{
if (ReferenceEquals(other, null))
return 1;
return drinkName.CompareTo(other.drinkName);
}
}
static class Screen
{
// Screen - Generic methods for handling in- and output ======================================= >
// Methods for screen handling in this object are:
//
// cls() Clear screen
// cup(row, col) Positions the curser to a position on the console
// inKey() Reads one pressed key (Returned value is : ConsoleKeyInfo)
// inStr() Handles String
// inInt() Handles Int
// inFloat() Handles Float(Singel)
// meny() Menu system , first invariable is Rubrik and 2 to 6 meny choises
// addSodaMenu() The options for adding bottles
// Clear Screen ------------------------------------------
static public void cls()
{
Console.Clear();
}
// Set Curser Position ----------------------------------
static public void cup(int column, int rad)
{
Console.SetCursorPosition(column, rad);
}
// Key Input --------------------------------------------
static public ConsoleKeyInfo inKey()
{
ConsoleKeyInfo in_key; in_key = Console.ReadKey(); return in_key;
}
// String Input -----------------------------------------
static public string inStr()
{
string in_string; in_string = Console.ReadLine(); return in_string;
}
// Int Input -------------------------------------------
static public int inInt()
{
int int_in; try { int_in = Int32.Parse(Console.ReadLine()); }
catch (FormatException) { Console.WriteLine("Input Error \b"); int_in = 0; }
catch (OverflowException) { Console.WriteLine("Input Owerflow\b"); int_in = 0; }
return int_in;
}
// Float Input -------------------------------------------
static public float inFloat()
{
float float_in; try { float_in = Convert.ToSingle(Console.ReadLine()); }
catch (FormatException) { Console.WriteLine("Input Error \b"); float_in = 0; }
catch (OverflowException) { Console.WriteLine("Input Owerflow\b"); float_in = 0; }
return float_in;
}
// Menu ------------------------------------------------
static public int meny(string rubrik, string m_val1, string m_val2)
{ // Meny med 2 val ---------------------
int menSvar; menyRubrik(rubrik); menyRad(m_val1); menyRad(m_val2); menSvar = menyInm();
return menSvar;
}
static public int meny(string rubrik, string m_val1, string m_val2, string m_val3)
{ // Meny med 3 val ---------------------
int menSvar; menyRubrik(rubrik); menyRad(m_val1); menyRad(m_val2); menyRad(m_val3); menSvar = menyInm();
return menSvar;
}
static public int meny(string rubrik, string m_val1, string m_val2, string m_val3, string m_val4)
{ // Meny med 4 val ---------------------
int menSvar; menyRubrik(rubrik); menyRad(m_val1); menyRad(m_val2); menyRad(m_val3); menyRad(m_val4); menSvar = menyInm();
return menSvar;
}
static public int meny(string rubrik, string m_val1, string m_val2, string m_val3, string m_val4, string m_val5)
{ // Meny med 5 val ---------------------
int menSvar; menyRubrik(rubrik); menyRad(m_val1); menyRad(m_val2); menyRad(m_val3); menyRad(m_val4); menyRad(m_val5); menSvar = menyInm();
return menSvar;
}
static public int meny(string rubrik, string m_val1, string m_val2, string m_val3, string m_val4, string m_val5, string m_val6)
{ // Meny med 6 val ---------------------
int menSvar; menyRubrik(rubrik); menyRad(m_val1); menyRad(m_val2); menyRad(m_val3); menyRad(m_val4); menyRad(m_val5); ; menyRad(m_val6); menSvar = menyInm();
return menSvar;
}
static void menyRubrik(string rubrik)
{ // Meny rubrik --------
cls(); Console.WriteLine("\n\t {0}\n----------------------------------------------------\n", rubrik);
}
static void menyRad(string menyVal)
{ // Meny rad --------
Console.WriteLine("\t {0}", menyVal);
}
static int menyInm()
{ // Meny inmating ------
int mVal; Console.Write("\n\t Menyval : "); mVal = inInt(); return mVal;
}
// Menu for adding bottles --------------------------------
static public void addSodaMenu()
{
cls();
Console.WriteLine("\tChoose a beverage please.");
Console.WriteLine("\t1. Coca Cola");
Console.WriteLine("\t2. Champis");
Console.WriteLine("\t3. Grappo");
Console.WriteLine("\t4. Pripps Blå lättöl");
Console.WriteLine("\t5. Spendrups lättöl");
Console.WriteLine("\t6. Ramlösa citron");
Console.WriteLine("\t7. Vichy Nouveu");
Console.WriteLine("\t9. Exit to main menu");
Console.WriteLine("\t--------------------\n");
}
// Screen - Slut <========================================
} // screen <----
class Sodacrate
{
// Sodacrate - Methods for handling arrays and lists of Soda-objects ======================================= >
// Methods for Soda handling in this object are:
//
// cls() Clear screen
//
//
private Soda[] bottles; //Create they array where we store the up to 25 bottles
private int antal_flaskor = 0; //Keep track of the number of bottles in the crate
//Inte Klart saknar flera träffar samt exception
public int find_Soda(string drinkname)
{
//Betyg C
//Beskrivs i läroboken på sidan 147 och framåt (kodexempel på sidan 149)
//Man ska kunna söka efter ett namn
//Man kan använda string-metoderna ToLower() eller ToUpper()
for (int i = 0; i < bottles.Length; i++)
{
if (bottles[i].Drink_name == drinkname)
return i;
}
return -1;
}
//Exception error
public void sort_Sodas()
{
int max = bottles.Length;
//Outer loop for complete [bottles]
for (int i = 1; i < max; i++)
{
//Inner loop for row by row
int nrLeft = max - i;
for (int j = 0; j < (max - i); j++)
{
if (bottles[j].Product_code > bottles[j + 1].Product_code)
{
int temp = bottles[j].Product_code;
bottles[j] = bottles[j + 1];
bottles[j + 1].Product_code = temp;
}
}
}
}
/*
//Exception error
public void sort_Sodas_name()
{
int max = bottles.Length;
//Outer loop for complete [bottles]
for (int i = 1; i < max; i++)
{
//Inner loop for row by row
int nrLeft = max - i;
for (int j = 0; j < (max - i); j++)
{
if (bottles[j].Drink_name > bottles[j + 1].Drink_name)
{
int temp = bottles[j].Drink_name;
bottles[j] = bottles[j + 1];
bottles[j + 1].Drink_name = temp;
}
}
}
}
*/
//Search for Product code
public int LinearSearch(int key)
{
for (int i = 0; i < bottles.Length; i++)
{
if (bottles[i].Product_code == key)
return i;
}
return -1;
}
//Contains the menu to choose from the crates methods
public void Run()
{
bottles[0] = new Soda("Coca Cola", "Soda", 5, 1);
bottles[1] = new Soda("Champis", "Soda", 6, 1);
bottles[2] = new Soda("Grappo", "Soda", 4, 1);
bottles[3] = new Soda("Pripps Blå", "beer", 6, 2);
bottles[4] = new Soda("Spendrups", "beer", 6, 2);
bottles[5] = new Soda("Ramlösa", "water", 4, 3);
bottles[6] = new Soda("Loka", "water", 4, 3);
bottles[7] = new Soda("Coca Cola", "Soda", 5, 1);
foreach (var beverage in bottles)
{
if (beverage != null)
Console.WriteLine(beverage);
}
Console.WriteLine("\n\tYou have {0} bottles in your crate:\n\n", bottleCount());
Console.WriteLine("\nTotal value of the crate\n");
int total = 0;
for (int i = 0; i < bottleCount(); i++)
{
total = total + (bottles[i].Drink_price);
}
/* int price = 0; //Causes exception error
foreach(var bottle in bottles)
{
price = price + bottle.Drink_price;
}
*/
Console.WriteLine("\tThe total value of the crate is {0} SEK.", total);
// Console.WriteLine("\tThe total value of the crate is {0} SEK.", price);
Screen.inKey();
Screen.cls();
int test = 0;
test = bottles[3].Product_code;
Console.WriteLine("Product code {0} is in slot {1}", test, 3);
Screen.inKey();
Console.WriteLine("Type 1, 2 or 3");
int prodcode = Screen.inInt();
Console.WriteLine(LinearSearch(prodcode));
Console.WriteLine("Product code {0} is in slot {1}", prodcode, (LinearSearch(prodcode)));
Console.WriteLine(bottles[(LinearSearch(prodcode))]);
Screen.inKey();
// sort_Sodas(); //Causes Exception error I want it to sort on either product code or product name
foreach (var beverage in bottles)
{
if (beverage != null)
Console.WriteLine(beverage);
}
}
//Print the content of the crate to the console
public void print_crate()
{
foreach (var beverage in bottles)
{
if (beverage != null)
Console.WriteLine(beverage);
//else
//Console.WriteLine("Empty slot");
}
Console.WriteLine("\n\tYou have {0} bottles in your crate:", bottleCount());
}
//Construct, sets the Sodacrate to hold 25 bottles
public Sodacrate()
{
bottles = new Soda[25];
}
// Count the ammounts of bottles in crate
public int bottleCount()
{
int cnt = antal_flaskor;
// Loop though array to get not empty element
foreach (var beverages in bottles)
{
if (beverages != null)
{
cnt++;
}
}
return cnt;
}
//Calculates the total value of the bottles in the crate
public int calc_total()
{
int temp = 0;
for (int i = 0; i < bottleCount(); i++)
{
temp = temp + (bottles[i].Drink_price);
}
return temp;
}
//Adds bottles in the crate.
public void add_Soda()
{
/*Metod för att lägga till en läskflaska
Om ni har information om både pris, läsktyp och namn
kan det vara läge att presentera en meny här där man kan
välja på förutbestämda läskflaskor. Då kan man också rätt enkelt
göra ett val för att fylla läskbacken med slumpade flaskor
*/
//I start of with adding 7 bottles to avoid having to add so many bottles testing functions. Remove block before release
bottles[0] = new Soda("Coca Cola", "Soda", 5, 1);
bottles[1] = new Soda("Champis", "Soda", 6, 1);
bottles[2] = new Soda("Grappo", "Soda", 4, 1);
bottles[3] = new Soda("Pripps Blå", "lättöl", 6, 2);
bottles[4] = new Soda("Spendrups", "lättöl", 6, 2);
bottles[5] = new Soda("Ramlösa citron", "mineralvatten", 4, 3);
bottles[6] = new Soda("Vichy Nouveu", "mineralvatten", 4, 3);
//<======================================================================================================= End block
int beverageIn = 0; //Creates the menu choice-variable
while (beverageIn != 9) //Exit this menu by typing 9 - This value should be different if we add more bottle types to add.
{
Screen.addSodaMenu(); //Calls the menu in the Screen-class
Console.WriteLine("You have {0} bottles in the crate.\n\nChoose :", bottleCount());
Screen.cup(8, 13);
int i = bottleCount(); //Keeps track of how many bottles we have in the crate. If the crate is full we get expelled out of this method
if (i == 25)
{ beverageIn = 9; }
else beverageIn = Screen.inInt(); //end
switch (beverageIn) //Loop for adding bottles to the crate exit by pressing 9
{
case 1:
i = bottleCount();
bottles[i] = new Soda("Coca Cola", "Soda", 5, 1);
i++;
break;
case 2:
i = bottleCount();
bottles[i] = new Soda("Champis", "Soda", 6, 1);
i++;
break;
case 3:
i = bottleCount();
bottles[i] = new Soda("Grappo", "Soda", 4, 1);
i++;
break;
case 4:
i = bottleCount();
bottles[i] = new Soda("Pripps Blå lättöl", "lättöl", 6, 2);
i++;
break;
case 5:
i = bottleCount();
bottles[i] = new Soda("Spendrups lättöl", "lättöl", 6, 2);
i++;
break;
case 6:
i = bottleCount();
bottles[i] = new Soda("Ramlösa citron", "mineralvatten", 4, 3);
i++;
break;
case 7:
i = bottleCount();
bottles[i] = new Soda("Vichy Nouveu", "mineralvatten", 4, 3);
i++;
break;
case 9:
i = bottleCount();
if (i == 25)
{
Console.WriteLine("\tThe crate is full\n\tGoing back to main menu. Press a key: ");
}
Console.WriteLine("Going back to main menu. Press a key: ");
break;
default: //Default will never kick in as I have error handling in Screen.inInt()
Console.WriteLine("Error, pick a number between 1 and 7 or 9 to end.");
break;
}
}
}
// Sodacrate - End <========================================
class Program
{
public static void Main(string[] args)
{
//Skapar ett objekt av klassen Sodacrate som heter Sodacrate
var Sodacrate = new Sodacrate();
Sodacrate.Run();
Console.Write("Press any key to continue . . . ");
Console.ReadKey(true);
}
}
}
}
In order to sort objects of a given kind you need to know how to compare two objects to begin with. You can sort an array of numbers because you know how to comparte 1 with 2 and 2 with -10 and so on.
Nowhere in your code are you defining how two sodas (that should be Soda by the way) compare to each other. One way to do this in c# (and .NET in general) is making your class implement a very specific interface named IComparable<T>:
public interface IComparable<T>
{
int CompareTo(T other);
}
CompareTo is what sorting algorithms like Array.Sort or Linq's OrderBy use (if not told otherwise). You need to do the same. T is a generic type, in your case you are interested in comparing sodas with sodas, so T would be Soda.
The CompareTo convention in .NET is as follows:
If this equals other return 0.
If this is less than other return -1.
If this is greater than other return 1.
null is considered to be smaller than any non null value.
Your implementation must follow this convention in order for built in sorting algorithms to work.
So first off, you need to define how you want your soda's to compare. By name? By price? All seem logical choices. If your problem specifies how sodas should compare then implement the comparison logic accordingly, otherwise choose a reasonable option.
I'll go with ordering by name, so I'd do the following:
public class Soda: IComparable<Soda>
{
....
public int CompareTo(Soda other)
{
if (ReferenceEquals(other, null))
return 1;
return drinkName.CompareTo(other.drinkName);
}
}
Because string implements IComparable<string>, implementing my own comparison logic is pretty straightforward.
Ok, now sodas know how to compare to each other and things like Array.Sort will work perfectly fine. Your own bubble sort algorithm should work well too, now that you know how to compare your softdrinks.
Another option would be to implement a IComparer<T> which is basically an object that knows how to compare two Sodas. Look into it, although in your case I think implementing IComparable<T> is a cleaner solution.
On another page, there are a few things about your code that can and should be improved:
soda should be named Soda. Classes should start with a capital letter (except maybe private nested ones).
Use properties instead of methods for Drink_name, Drink_price, Drink_type etc. and better yet, use autoimplemented properties to reduce boilerplate code.
Remove Drink form property names, the class is named Soda, so Drink is pretty much redundant not adding any useful information; its just making property names longer for no reason.
If you insist on keeping Drink use camel casing and remove _: DrinkName, DrinkType, etc.

Split a range sequence into multiple string c#,linq [closed]

Closed. This question needs debugging details. It is not currently accepting answers.
Edit the question to include desired behavior, a specific problem or error, and the shortest code necessary to reproduce the problem. This will help others answer the question.
Closed 7 years ago.
Improve this question
Not sure why question is being marked as offtopic, where as so called desired behaviour is included within the question post!
I am trying to write this program that takes two inputs:
• a set of include intervals
• and a set of exclude intervals
The sets of intervals can be given in any order, and they may be empty or overlapping. The program should output the result of taking all the includes and “remove” the excludes. The output should be given as non-overlapping intervals in a sorted order.
Intervals will contain Integers only
Example :
Includes: 50-600, 10-100
Excludes: (empty)
Output: 10-600
Includes: 10-100, 200-300, 400-600
Excludes: 95-205, 410-420
Output: 10-94, 206-300, 400-409, 421-600
I tried to populate two Enumerable Range from include and excludes (after splitting,parsing ), but didn't find any efficient way of implementing this afterwards.
string[] _break = _string.Split(',');
string[] _breakB = _stringB.Split(',');
string[] res = new string[_break.Length + 1];
string[] _items, _itemsB;
List < int > _back = new List < int > ();
int count = 0;
foreach(var _item in _break) {
_items = _item.Split('-');
var a = Enumerable.Range(int.Parse(_items[0]), (int.Parse(_items[1]) - int.Parse(_items[0]) + 1)).ToList();
foreach(var _itemB in _breakB) {
_itemsB = _itemB.Split('-');
var b = Enumerable.Range(int.Parse((_itemsB[0])), (int.Parse(_itemsB[1]) - int.Parse((_itemsB[0])) + 1)).ToList();
var c = a.Except < int > (b).ToList();
/// different things tried here, but they are not good
res[count] = c.Min().ToString() + "-" + c.Max().ToString();
count++;
}
}
return res;
Any input will be of great help
You can use the Built-in SortedSet<T> collection to do most of the work for you like this:
The SortedSet<T> collection implements the useful UnionWith and ExceptWith methods which at least makes the code quite easy to follow:
private void button1_Click(object sender, EventArgs e)
{
string[] includeRanges = _string.Text.Replace(" ", "").Split(',');
string[] excludeRanges = _stringB.Text.Replace(" ", "").Split(',');
string[] includeRange, excludeRange;
SortedSet<int> includeSet = new SortedSet<int>();
SortedSet<int> excludeSet = new SortedSet<int>();
// Create a UNION of all the include ranges
foreach (string item in includeRanges)
{
includeRange = item.Split('-');
includeSet.UnionWith(Enumerable.Range(int.Parse(includeRange[0]), (int.Parse(includeRange[1]) - int.Parse(includeRange[0]) + 1)).ToList());
}
// Create a UNION of all the exclude ranges
foreach (string item in excludeRanges)
{
excludeRange = item.Split('-');
excludeSet.UnionWith(Enumerable.Range(int.Parse(excludeRange[0]), (int.Parse(excludeRange[1]) - int.Parse(excludeRange[0]) + 1)).ToList());
}
// Exclude the excludeSet from the includeSet
includeSet.ExceptWith(excludeSet);
//Format the output using a stringbuilder
StringBuilder sb = new StringBuilder();
int lastValue = -1;
foreach (int included in includeSet)
{
if (lastValue == -1)
{
sb.Append(included + "-");
lastValue = included;
}
else
{
if (lastValue == included - 1)
{
lastValue = included;
}
else
{
sb.Append(lastValue + ",");
sb.Append(included + "-");
lastValue = included;
}
}
}
sb.Append(lastValue);
result.Text = sb.ToString();
}
This should work faster than SortedSet trick, at least for large intervals. Idea is like:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text.RegularExpressions;
namespace Test
{
using Pair = Tuple<int, int>; //for brevity
struct Point //point of an interval
{
public enum Border { Left, Right };
public enum Interval { Including, Excluding };
public int Val;
public int Brdr;
public int Intr;
public Point(int value, Border border, Interval interval)
{
Val = value;
Brdr = (border == Border.Left) ? 1 : -1;
Intr = (int)interval;
}
public override string ToString() =>
(Brdr == 1 ? "L" : "R") + (Intr == 0 ? "+ " : "- ") + Val;
}
class Program
{
static IEnumerable<Pair> GetInterval(string strIn, string strEx)
{
//a func to get interval border points from string:
Func<string, Point.Interval, IEnumerable<Point>> parse = (str, intr) =>
Regex.Matches(str, "[0-9]+").Cast<Match>().Select((s, idx) =>
new Point(int.Parse(s.Value), (Point.Border)(idx % 2), intr));
var INs = parse(strIn, Point.Interval.Including);
var EXs = parse(strEx, Point.Interval.Excluding);
var intrs = new int[2]; //current interval border control IN[0], EX[1]
int start = 0; //left border of a new resulting interval
//put all points in a line and loop:
foreach (var p in INs.Union(EXs).OrderBy(x => x.Val))
{
//check for start (close) of a new (cur) interval:
var change = (intrs[p.Intr] == 0) ^ (intrs[p.Intr] + p.Brdr == 0);
intrs[p.Intr] += p.Brdr;
if (!change) continue;
var In = p.Intr == 0 && intrs[1] == 0; //w no Ex
var Ex = p.Intr == 1 && intrs[0] > 0; //breaks In
var Open = intrs[p.Intr] > 0;
var Close = !Open;
if (In && Open || Ex && Close)
{
start = p.Val + p.Intr; //exclude point if Ex
}
else if (In && Close || Ex && Open)
{
yield return new Pair(start, p.Val - p.Intr);
}
}
}
static void Main(string[] args)
{
var strIN = "10-100, 200-300, 400-500, 420-480";
var strEX = "95-205, 410-420";
foreach (var i in GetInterval(strIN, strEX))
Console.WriteLine(i.Item1 + "-" + i.Item2);
Console.ReadLine();
}
}
}
So, you task could be separated to the list of subtasks:
Parse a source line of intervals to the list of objects
Concatinate intervals if they cross each over
Excludes intervals 'excludes' from 'includes'
I published my result code here: http://rextester.com/OBXQ56769
The code could be optimized as well, but I wanted it to be quite simple. Hope it will help you.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text.RegularExpressions;
namespace ConsoleApplication
{
public class Program
{
private const string Includes = "10-100, 200-300, 400-500 ";
private const string Excludes = "95-205, 410-420";
private const string Pattern = #"(\d*)-(\d*)";
public static void Main(string[] args)
{
var includes = ParseIntevals(Includes);
var excludes = ParseIntevals(Excludes);
includes = ConcatinateIntervals(includes);
excludes = ConcatinateIntervals(excludes);
// The Result
var result = ExcludeFromInclude(includes, excludes);
foreach (var interval in result)
{
Console.WriteLine(interval.Min + "-" + interval.Max);
}
}
/// <summary>
/// Excludes intervals 'excludes' from 'includes'
/// </summary>
public static List<Interval> ExcludeFromInclude(List<Interval> includes, List<Interval> excludes)
{
var result = new List<Interval>();
if (!excludes.Any())
{
return includes.Select(x => x.Clone()).ToList();
}
for (int i = 0; i < includes.Count; i++)
{
for (int j = 0; j < excludes.Count; j++)
{
if (includes[i].Max < excludes[j].Min || includes[i].Min > excludes[j].Max)
continue; // no crossing
//1 Example: includes[i]=(10-20) excludes[j]=(15-25)
if (includes[i].Min < excludes[j].Min && includes[i].Max <= excludes[j].Max)
{
var interval = new Interval(includes[i].Min, excludes[j].Min - 1);
result.Add(interval);
break;
}
//2 Example: includes[i]=(10-25) excludes[j]=(15-20)
if (includes[i].Min <= excludes[j].Min && includes[i].Max >= excludes[j].Max)
{
if (includes[i].Min < excludes[j].Min)
{
var interval1 = new Interval(includes[i].Min, excludes[j].Min - 1);
result.Add(interval1);
}
if (includes[i].Max > excludes[j].Max)
{
var interval2 = new Interval(excludes[j].Max + 1, includes[i].Max);
result.Add(interval2);
}
break;
}
//3 Example: includes[i]=(15-25) excludes[j]=(10-20)
if (includes[i].Min < excludes[j].Max && includes[i].Max > excludes[j].Max)
{
var interval = new Interval(excludes[j].Max + 1, includes[i].Max);
result.Add(interval);
break;
}
}
}
return result;
}
/// <summary>
/// Concatinates intervals if they cross each over
/// </summary>
public static List<Interval> ConcatinateIntervals(List<Interval> intervals)
{
var result = new List<Interval>();
for (int i = 0; i < intervals.Count; i++)
{
for (int j = 0; j < intervals.Count; j++)
{
if (i == j)
continue;
if (intervals[i].Max < intervals[j].Min || intervals[i].Min > intervals[j].Max)
{
Interval interval = intervals[i].Clone();
result.Add(interval);
continue; // no crossing
}
//1
if (intervals[i].Min < intervals[j].Min && intervals[i].Max < intervals[j].Max)
{
var interval = new Interval(intervals[i].Min, intervals[j].Max);
result.Add(interval);
break;
}
//2
if (intervals[i].Min < intervals[j].Min && intervals[i].Max > intervals[j].Max)
{
Interval interval = intervals[i].Clone();
result.Add(interval);
break;
}
//3
if (intervals[i].Min < intervals[j].Max && intervals[i].Max > intervals[j].Max)
{
var interval = new Interval(intervals[j].Min, intervals[i].Max);
result.Add(interval);
break;
}
//4
if (intervals[i].Min > intervals[j].Min && intervals[i].Max < intervals[j].Max)
{
var interval = new Interval(intervals[j].Min, intervals[j].Max);
result.Add(interval);
break;
}
}
}
return result.Distinct().ToList();
}
/// <summary>
/// Parses a source line of intervals to the list of objects
/// </summary>
public static List<Interval> ParseIntevals(string intervals)
{
var matches = Regex.Matches(intervals, Pattern, RegexOptions.IgnoreCase);
var list = new List<Interval>();
foreach (Match match in matches)
{
var min = int.Parse(match.Groups[1].Value);
var max = int.Parse(match.Groups[2].Value);
list.Add(new Interval(min, max));
}
return list.OrderBy(x => x.Min).ToList();
}
/// <summary>
/// Interval
/// </summary>
public class Interval
{
public int Min { get; set; }
public int Max { get; set; }
public Interval()
{
}
public Interval(int min, int max)
{
Min = min;
Max = max;
}
public override bool Equals(object obj)
{
var obj2 = obj as Interval;
if (obj2 == null) return false;
return obj2.Min == Min && obj2.Max == Max;
}
public override int GetHashCode()
{
return this.ToString().GetHashCode();
}
public override string ToString()
{
return string.Format("{0}-{1}", Min, Max);
}
public Interval Clone()
{
return (Interval) this.MemberwiseClone();
}
}
}
}
Lots of ways to solve this. The LINQ approach hasn't been discussed yet - this is how I would do it:
// declaring a lambda fn because it's gonna be used by both include/exclude
// list
Func<string, IEnumerable<int>> rangeFn =
baseInput =>
{
return baseInput.Split (new []{ ',', ' ' },
StringSplitOptions.RemoveEmptyEntries)
.SelectMany (rng =>
{
var range = rng.Split (new []{ '-' },
StringSplitOptions.RemoveEmptyEntries)
.Select(i => Convert.ToInt32(i));
// just in case someone types in
// a reverse range (e.g. 10-5), LOL...
var start = range.Min ();
var end = range.Max ();
return Enumerable.Range (start, (end - start + 1));
});
};
var includes = rangeFn (_string);
var excludes = rangeFn (_stringB);
var result = includes.Except (excludes).Distinct().OrderBy(r => r);

C# NullReferenceException Thrown: My StudentList static class array is null

I have been trying to figure out what is happening with my code. I wrote an application where the user is able to enter marks of the student through a GUI application. The first form shows options, the next form is to enter the student information (name, number, mark), and the last form is to display a summary of the student information (total number of students, highest mark, lowest mark, name of student with highest mark, list of students).
To store all the student entries, I had made a student class. I created a static Student array and placed it in my ProgramFunctions class file (which is all static methods).
When I try to run the form which displays the student summary, thats where it crashes - If I look at the Auto's tab, it tells me the value of student[a] is null (I made use of a for loop to go through each student object in the array). I did trace through the adding of students and it does show that I have added new entries to the Student array.
Exceptions would be thrown at my calculation methods (highestMark, lowestMark, average). Here is my code:
class ProgramFunctions
{
private static Student[] studentList = new Student[25];
private static int counter = 0;
public static void addNewStudent(Student newStudent)
{
if (studentList.Count() == counter)
{
MessageBox.Show("The Student List is Full", "List is Full");
}
else
{
studentList[counter] = newStudent;
counter++;
}
}
public static void displayErrorMessage(String message, String title)
{
MessageBox.Show(message, title);
}
public static TextBox validateTextBox(int textboxNumber, TextBox thisTextBox)
{
if (textboxNumber.Equals(1)) //Student Name textbox
{
if (thisTextBox.Text.Length < 0 || thisTextBox.Text.Length > 100)
{
displayErrorMessage("The Student Name specified is out of allowed region (greater than 100 or less than 0 characters. Please fix this", "Student Name Error");
}
else
{
thisTextBox.Text = thisTextBox.Text.Trim();
return thisTextBox;
}
}
else if (textboxNumber.Equals(2)) //Student number text box (only 10 characters allowed)
{
if (thisTextBox.Text.Length < 0 || thisTextBox.Text.Length > 10)
{
displayErrorMessage("The student number you specified is greater than 10 characters or less than 0. Please fix this", "Student Number Error");
}
else
{
thisTextBox.Text = thisTextBox.Text.Trim();
return thisTextBox;
}
}
else
{
if (thisTextBox.Text.Length > 2 || thisTextBox.Text.Length < 0)
{
displayErrorMessage("Invalid Length for exam mark", "Invalid Exam Mark");
}
else
{
thisTextBox.Text = thisTextBox.Text.Trim();
return thisTextBox;
}
}
return null;
}
public static int getMaximumMarkPosition()
{
int highestMark = -999;
int positionFound = -1;
for (int a = 0; a < counter; a++)
{
if (studentList[a].getExamMark > highestMark)
{
highestMark = studentList[a].getExamMark; //This is where the error would occur
positionFound = a;
}
}
return positionFound;
}
public static int getHighestMark(int position)
{
return studentList[position].getExamMark;
}
public static int getLowestMark(int position)
{
return studentList[position].getExamMark;
}
public static string getHighestStudentMarkName(int position)
{
return studentList[position].getStudentName;
}
public static int getLowestMarkPosition()
{
int lowestMark = 999;
int positionFound = -1;
int studentMark = 0;
for (int a = 0; a < studentList.Count(); a++)
{
studentMark = studentList[a].getExamMark; //This is where the error would occur
if (studentMark < lowestMark)
{
lowestMark = studentMark;
positionFound = a;
}
}
return positionFound;
}
public static double calculateClassAverage()
{
double sum = 0;
double average = 0;
for (int a = 0; a < studentList.Count(); a++)
{
sum = sum + studentList[a].getExamMark;
}
average = sum / studentList.Count();
return average;
}
public static int getTotalNumberOfStudents()
{
return counter;
}
public static RichTextBox getTextBoxData(RichTextBox thisTextBox)
{
thisTextBox.Text = "STUDENT MARK DATA: \n\n";
for (int a = 1; a < studentList.Count(); a++)
{
Student currentStudent = returnStudentInformation(a);
thisTextBox.Text = thisTextBox.Text + "\n" + currentStudent.getStudentName + "\t\t" + currentStudent.getExamMark + "\t" + currentStudent.getStudentNumber;
}
return thisTextBox;
}
public static Student returnStudentInformation(int index)
{
return studentList[index];
}
}
}
It seems to me that if the student list isn't full accessing any index at counter or higher will result in a null object. I would suggest only looping up to counter:
for (int a = 1; a < counter; a++)
{
Student currentStudent = returnStudentInformation(a);
thisTextBox.Text = thisTextBox.Text + "\n" + currentStudent.getStudentName + "\t\t" + currentStudent.getExamMark + "\t" + currentStudent.getStudentNumber;
}
All this begs the question why use a static array for dynamic data when List<T> is available and is made for dynamic data.

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