Use a multidimensional array of strings to write to file - c#

I'm trying to develop a simple EPOS system that records inventory and processes transactions. At the moment I want it to write the contents of my arrays (Product, Price, Size, Stock Level) to file using Streamwriter as well as a random date at the top but I haven't been able to crack it. My global variables declared for these arrays are below.
readonly static string[] Products = { "1989 Jersey", "1977 Jersey", "2001 Jersey", "1986 Jersey", "1990 Jersey", "2005 Jersey", "1992 Jersey", "1996 Jersey", "1985 Jersey", "1989 Jersey", "1991 Jersey", "1992 Jersey", "1986 Jersey"};
readonly static decimal[] Price = {26m, 24m, 21m, 25m, 19m, 22m, 23m, 18m, 16.50m, 17.50m, 14m, 20m, 17.50m};
readonly static string[] Sizes = {"Extra Small", "Small", "Medium", "Large", "Extra Large"};
readonly static int[,] StartingStock = {{ 1, 1, 1, 1, 1 },
{ 1, 1, 1, 1, 1 },
{ 1, 1, 1, 1, 1 },
{ 1, 1, 1, 1, 1 },
{ 1, 1, 1, 1, 1 },
{ 1, 1, 1, 1, 1 },
{ 1, 1, 1, 1, 1 },
{ 1, 1, 1, 1, 1 },
{ 1, 1, 1, 1, 1 },
{ 1, 1, 1, 1, 1 },
{ 1, 1, 1, 1, 1 },
{ 1, 1, 1, 1, 1 },
{ 1, 1, 1, 1, 1 }};
I am currently trying to get my code to work. I am invoking the method above in a Form Load event and it only passes the contents at Index 0,0 to file.
private void WriteToFileOpeningStock()
{
string[] Productlist = { Products[0], Sizes[0] };
try
{
//enable StreamwWriter Object
StreamWriter outputfile;
// create file
outputfile = File.CreateText("ProductList.txt");
//writing array contents to file
for (int index = 0; index < Productlist.Length; index++)
{
outputfile.WriteLine(Productlist[index]);
outputfile.WriteLine("");
}
outputfile.Close();
MessageBox.Show("Data Entered");
}
catch
{
MessageBox.Show("Error");
}
I tried to write string[] Productlist = { Products[0-12], Sizes[0-4] }; to get it to pass all of the array contents but it throws an exception "Index was outside the bounds of the array". I am new to C# and programming so any help would be very much appreciated.

You are looping through ProductList:
string[] Productlist = { Products[0], Sizes[0] };
This only has the first index of the Product inside and the first index of Sizes inside. So there are only two values it will output.
You need to create two nested for loops, looping through both Products and Sizes

If you just looking to list the products you could do something like this
try
{
//enable StreamwWriter Object
StreamWriter outputfile;
// create file
outputfile = File.CreateText("ProductList.txt");
//writing array contents to file
for (int index = 0; index < Products.Length; index++)
{
outputfile.WriteLine(Products[index]);
outputfile.WriteLine("");
}
outputfile.Close();
MessageBox.Show("Data Entered");
}
catch
{
MessageBox.Show("Error");
}
In general I would Create a Class to hold your product. Something like
public class Product
{
public string ProductName { get; set; }
public List<string> Sizes { get; set; }
public decimal Price { get; set; }
}
then you can do something like this to convert to the new class
Productlist = new List<Product>();
for (int x = 0; x < Products.Length; x++)
{
Productlist.Add(new Product()
{
ProductName = Products[x],
Price = Price[x],
Sizes = Sizes.ToList()
});
}
WriteToFileOpeningStock();
Then you could make the following changes to list the products in a file
private void WriteToFileOpeningStock()
{
try
{
//enable StreamwWriter Object
StreamWriter outputfile;
// create file
outputfile = File.CreateText("ProductList.txt");
//writing array contents to file
foreach(Product product in Productlist)
{
outputfile.WriteLine(product.ProductName);
outputfile.WriteLine("");
}
outputfile.Close();
MessageBox.Show("Data Entered");
}
catch
{
MessageBox.Show("Error");
}
}

Related

linq order by based on multiple columns and various crietria

I have data arranged in this order in sql.
Now, I want to order this list with both QuestionDataTypeId and DisplayOrder, but want this QuestionDataTypeId = 0 at last. so finally result will be like first row = 6 then 7 then 8 and then 1 to 5.
I want to achieve this with C# and linq.
What I have tried so far?
here is my code but it's not working.
var data = entity
.OrderByDescending(m => m.QuestionDataTypeId == 0)
.ThenBy(m => m.QuestionDataTypeId)
.ThenBy(m => m.DisplayOrder);
I have fixed this with merging 2 different variables sorted separately for QuestionDataTypeId = 0 and all other QuestionDataTypeId, but just want to know what will be the proper linq for this case in single line.
any help would be really appreciated. thanks!
Try replace QuestionDataTypeId where value = 0
.OrderBy(x=>x.QuestionDataTypeId==0?int.MaxValue:x.QuestionDataTypeId)
.ThenBy(t=>t.DisplayOrder)
You can write your own comparer for OrderBy
Sample data structure:
public record Table
{
public Table(int qdtId, int displayOrder, string text)
{
QuestionDataTypeId = qdtId;
DisplayOrder = displayOrder;
Text = text;
}
public int QuestionDataTypeId { get; set; }
public int DisplayOrder { get; set; }
public string Text { get; set; }
}
public class TableComparer : IComparer<Table>
{
public int Compare(Table? x, Table? y)
{
if(x.QuestionDataTypeId!= 0 && y.QuestionDataTypeId!=0 || x.QuestionDataTypeId == 0 && y.QuestionDataTypeId == 0)
{
return y.QuestionDataTypeId.CompareTo(x.QuestionDataTypeId);
}
return x.QuestionDataTypeId == 0 && y.QuestionDataTypeId != 0 ? int.MinValue : int.MaxValue;
}
}
Then in the code:
List<StringConcatBug.Table> list = new()
{
new(0, 1, "Comfortable"),
new(0, 2,"attainable"),
new(0, 3,"recent goal"),
new(0, 4,"comfortable"),
new(2, 2,"Last Name"),
new(3, 3,"Email"),
new(0, 5, "feeling"),
new(1, 1, "First Name"),
};
var ordered = list.OrderByDescending(t=>t,new TableComparer());
foreach(var v in ordered) { Console.WriteLine(v);}
Output
Table { QuestionDataTypeId = 1, DisplayOrder = 1, Text = First Name }
Table { QuestionDataTypeId = 2, DisplayOrder = 2, Text = Last Name }
Table { QuestionDataTypeId = 3, DisplayOrder = 3, Text = Email }
Table { QuestionDataTypeId = 0, DisplayOrder = 1, Text = Comfortable }
Table { QuestionDataTypeId = 0, DisplayOrder = 2, Text = attainable }
Table { QuestionDataTypeId = 0, DisplayOrder = 3, Text = recent goal }
Table { QuestionDataTypeId = 0, DisplayOrder = 4, Text = comfortable }
Table { QuestionDataTypeId = 0, DisplayOrder = 5, Text = feeling }
I usually use this algorithm
var mult=100000; // You can select a different number depending how many records of
// the same type you expecting; Numbers should not overlap
var data = entity
.OrderBy(m => (m.QuestionDataTypeId*mult + m.DisplayOrder))
.....

Binding multiple values to different variables in c# using for loop

How should i bind the values without using index no. as above, how can use forLoop here if possible. in query i gor 14 rows and 4 columns.
public class SLRInvestmentPrev
{
[DbCol("BOOK_VALUE")]
public double BOOK_VALUE { get; set; }
[DbCol("INSTRUMENT_ID")]
public int instrument_id { get; set; }
}
Public void Compute()
{
var slrinvestmentPrev = Database.BindList<SLRInvestmentPrev>(Transaction, #"Query here");
View["BOOK_VALUE_HTM0"] = slrinvestmentPrev[0].BOOK_VALUE;
View["BOOK_VALUE_HTM1"] = slrinvestmentPrev[1].BOOK_VALUE;
View["BOOK_VALUE_HTM2"] = slrinvestmentPrev[2].BOOK_VALUE;
View["BOOK_VALUE_HTM3"] = slrinvestmentPrev[3].BOOK_VALUE;
View["BOOK_VALUE_HFT1"] = slrinvestmentPrev[4].BOOK_VALUE;
View["BOOK_VALUE_HFT2"] = slrinvestmentPrev[5].BOOK_VALUE;
View["BOOK_VALUE_HFT3"] = slrinvestmentPrev[6].BOOK_VALUE;
View["BOOK_VALUE_HFT4"] = slrinvestmentPrev[7].BOOK_VALUE;
View["BOOK_VALUE_HFT5"] = slrinvestmentPrev[8].BOOK_VALUE;
View["BOOK_VALUE_AFS1"] = slrinvestmentPrev[9].BOOK_VALUE;
View["BOOK_VALUE_AFS2"] = slrinvestmentPrev[10].BOOK_VALUE;
View["BOOK_VALUE_AFS3"] = slrinvestmentPrev[11].BOOK_VALUE;
View["BOOK_VALUE_AFS4"] = slrinvestmentPrev[12].BOOK_VALUE;
View["BOOK_VALUE_AFS5"] = slrinvestmentPrev[13].BOOK_VALUE;
}
given your books are HTM0 to AFS5 you could do something like
List<String> booklist = new List<string>(new String[] { "BOOK_VALUE_HTM0", "BOOK_VALUE_HTM1", "BOOK_VALUE_HTM2",<.....> "BOOK_VALUE_AFS5" } ); // or populate from some other means
int index = 0;
foreach (String sbook in booklist)
{
View[sbook] = slrinvestmentPrev[index].BOOK_VALUE;
index++
}
how to bind that right side index values to different variables using
for loop or is there any way to make code short and being error free
if suppose to be rows no are less than hard coded index values?
So you need a way to bind your names to the indexes, one way it to use a Dictionary:
var nameIndexes = new Dictionary<int, string>()
{
{ 0, "BOOK_VALUE_HTM0" }, { 1, "BOOK_VALUE_HTM1" }, { 2, "BOOK_VALUE_HTM2" }, { 3, "BOOK_VALUE_HTM3" },
{ 4, "BOOK_VALUE_HFT1" }, { 5, "BOOK_VALUE_HFT2" }, { 6, "BOOK_VALUE_HFT3" }, { 7, "BOOK_VALUE_HFT4" }, { 8, "BOOK_VALUE_HFT5" },
{ 9, "BOOK_VALUE_AFS1" }, { 10, "BOOK_VALUE_AFS2" }, { 11, "BOOK_VALUE_AFS3" }, { 12, "BOOK_VALUE_AFS4" }, { 13, "BOOK_VALUE_AFS5" }
};
for(int i = 0; i < slrinvestmentPrev.Count; i++)
{
View[nameIndexes[i]] = slrinvestmentPrev[i].BOOK_VALUE;
}
If the index always starts with 0 and has no gaps you could also use a List<string> or string[].

what is the c# object to save the data in this formate

I have this string
string[] xInBGraph = { "IVR", "Agents", "Abandoned", "Cancelled" };
and I have these values:
int ivr = 1;
int agents = 2;
int abandoned = 3;
int cancelled = 4;
What I need
To make an array for each element in the array xInBGraph in which the new array should contain one value and the other values are zero. For example This is how the final result will be
IVR = [ivr =1, 0 , 0 ,0, 0]
Agents = [0, agents=2, 0,0]
Abandoned = [0, 0, abandoned = 3, 0]
Cancelled = [0, 0, 0, cancelled = 0]
what I have tried
making 4 arrays and fill them in the correct data. It works good. However, my altimate goal is to transfer that final result to a json object. I need to return just on json object. but in my case, which is 4 arrays, I must return 4 json objects which is not good for my situation. I need to return just on json object. So, what is the object in c# that can have the mentioned data and can be transfer to one json object?
I am using json.net library so I can easily change any c# object to json object
Edit
I made these four arrays:
int[] ivrArray = { Tivr, 0, 0, 0};
int[] agentsArray = { 0, tTotalCallsByAgent, 0, 0 };
int[] abandonedArray = { 0, 0, tTotalAbandoned, 0};
int[] canceledArray = { 0, 0, 0, Tcancel};
Now all I need is something to save the label of each array and the array in one row.
I would suggest you use a Dictionary. Specifically,
Dictionary<string,int[]> dictionary = new Dictionary<string,int[]>()
{
{ "IVR", new int[] {1,0,0,0} },
{ "Agents", new int[] {0,2,0,0} },
{ "Abandoned", new int[] {0,0,3,0} },
{ "Cancelled", new int[] {0,0,0,0} },
}
Hope this is what you are expecting
string[] xInBGraph = { "IVR", "Agents", "Abandoned", "Cancelled" };
List<string[]> final = new List<string[]>();
for (int i = 0; i < xInBGraph.Count(); i++)
{
List<string> array = new List<string>();
for (int x = 0; x < xInBGraph.Count(); x++)
{
if (x == i)
{
array.Add(xInBGraph[i].ToString() + "=" + x);
}
else
{
array.Add("0");
}
}
final.Add(array.ToArray());
}
string json = JsonConvert.SerializeObject(final, Formatting.Indented);
Output
[ [ "IVR=0", "0", "0", "0" ], [ "0", "Agents=1", "0", "0" ], [ "0", "0", "Abandoned=2", "0" ], [ "0", "0", "0", "Cancelled=3" ] ]

how to sort a list then sort a subset of that list

I have a collection of lines. Each line is a collection of fields. It is very easy to find column 1 and sort by its content:
_lines = lines.OrderBy(l => l.Fields.Find(f => f.ColumnNumber == 1).Content).ToList();
But how do I then sort a subset of this list? I want to sort by f.ColumnNumber == 3 where (f.ColumnNumber == 1).Content is 6.
So my line collection looks like this:
Col1, Col2, Col3
1, data, data
5, data, data
6, data, Chuck
6, data, Chuck
6, data, Jeffster
6, data, Jeffster
6, data, Grunke
6, data, Gertrude
8, data, data
9, data, data
I want to sort by col1, then sort only col1's where col1 == 6 but sort by col3.
Is there a way to do this in c#? I can't seem to find the magic formula.
EDIT:
My sample data is a little over simplified. Some lines have 3 columns, other lines have more or less columns. So when I use the .ThenBy extention, if I am trying to subsort lines on col 3 but say line 9 only has one column, I get an object reference not set to an instance of an object exception.
Here is a better example of the sample data:
Col1, Col2, Col3, Col4
1, data, data, data
5, data, data
6, data, Chuck
6, data, Chuck
6, data, Jeffster
6, data, Jeffster
6, data, Grunke
6, data, Gertrude
8, data, data
9, data
Code 1 lines have 4 columns.
Code 5 lines have 3.
Code 6 lines have 3 - and I need to sort by col 3 alphabetically.
Code 8 lines have 3 columns.
Code 9 lines have 2.
There is no guarantee the list is sorted at all. So I need first of all to have the lines sorted by that first column 1 - 9, then I need only code 6's to be sorted by col 3.
EDIT 2:
My class structure is somewhat complicated so I was trying to keep it simple as possible hoping it would be sufficient, but it looks like that his not the case so let me share with you the class definition:
public class Field : IField
{
public FieldSpecification Specification { get; set; }
public string Content { get; set; }
}
public class FieldSpecification
{
public int ColumnNumber { get; set; }
public int Length { get; set; }
public int StartPosition { get; set; }
public int EndPosition { get { return StartPosition + Length - 1; } }
public Justification Justification { get; set; }
public char PadCharacter { get; set; }
}
Then I have a bunch of lines that conform to the ILine interface
public interface ILine
{
List<IField> Fields { get; set; }
int Credits { get; }
int Debits { get; }
BigInteger Hash { get; }
}
So technically above I show something like field.ColumnNumber, but it should be field.Specification.ColumnNumber.
The objective is to build fixed width files according to specifications that can change. So each line has a collection of fields with specifications, and then data can go into the content, and the specification can help do validation: formatting validation.
I was hoping there would be a way to sort subsets of lists using linq, but I may need to deconstruct my final collection of lines, sort it, then reconstruct the collection. I was hoping to avoid that.
You could use the ThenBy extension.
Looking at your desired output, it seems something as simple as,
var output = lines.Select(l => new
{
Col1 = int.Parse(l.Fields.Find(f => f.ColumnNumber == 1).Content),
Col2 = l.Fields.Find(f => f.ColumnNumber == 2).Content,
Col3 = l.Fields.Find(f => f.ColumnNumber == 3).Content
}).OrderBy(l => l.Col1).ThenBy(l => l.Col3);
would suffice.
If, for some reason, you only want to order the sub list when Col1 is 6,
var output = lines.Select(l => new
{
Col1 = int.Parse(l.Fields.Find(f => f.ColumnNumber == 1).Content),
Col2 = l.Fields.Find(f => f.ColumnNumber == 2).Content,
Col3 = l.Fields.Find(f => f.ColumnNumber == 3).Content
}).OrderBy(l => l.Col1).ThenBy(l => l.Col1 == 6 ? l.Col3 : null);
One last caveat, depending on the type of Fields there is probably a better approach to all of this.
It can be done via the ThenBy extension method; in general, the concept is known as lexicographical order.
If I can assume that you class definition is this:
public class Datum
{
public int ID { get; set; }
public string[] Cols { get; set; }
}
Then I can define the data like this:
var data = new []
{
new Datum() { ID = 1, Cols = new [] { "data", "data", "data", }, },
new Datum() { ID = 5, Cols = new [] { "data", "data", }, },
new Datum() { ID = 6, Cols = new [] { "data", "Chuck", }, },
new Datum() { ID = 6, Cols = new [] { "data", "Chuck", }, },
new Datum() { ID = 6, Cols = new [] { "data", "Jeffster", }, },
new Datum() { ID = 6, Cols = new [] { "data", "Jeffster", }, },
new Datum() { ID = 6, Cols = new [] { "data", "Grunke", }, },
new Datum() { ID = 6, Cols = new [] { "data", "Gertrude", }, },
new Datum() { ID = 8, Cols = new [] { "data", "data", }, },
new Datum() { ID = 9, Cols = new [] { "data", }, },
};
And then I can sort like this:
var sorted =
from d in data
let key =
String.Format("{0:0000}", d.ID)
+ (d.ID != 6 ? "" : "-" + d.Cols[1])
orderby key
select d;
I get these results:

using linq query to find value that differs from previously found value

Say i have a class that contains these items publicly accessible via properties:
class MyClass
{
int switch1; //0 or 1
int switch2; //0 or 1
int switch3; //0 or 1
}
This class represents switch states, and each time a switch state changes, i would like to add it to my transition list
I have a large sorted list that contains instances of this class and would like to use a query to capture only the entries in my list where the switch state for any switch changes.
Is this possible using a linq query?
try this:
Assuming your class looks like:
public class State
{
public int Id { get; set; }
public int Switch1 { get; set; }
public int Switch2 { get; set; }
public int Switch3 { get; set; }
public override bool Equals(object obj)
{
var other = obj as State;
if (other != null)
{
return Switch1 == other.Switch1 &&
Switch2 == other.Switch2 &&
Switch3 == other.Switch3;
}
return false;
}
}
I just added an Equals() to compare flags and my Id field is purely to demonstrate which items changed.
We can then craft a LINQ query like:
State previous = null;
var transitions = list.Where(s =>
{
bool result = !s.Equals(previous);
previous = s;
return result;
})
.ToList();
Not elegant, but it works, if you had this data set:
var list = new List<State>
{
new State { Id = 0, Switch1 = 0, Switch2 = 0, Switch3 = 0 },
new State { Id = 1, Switch1 = 0, Switch2 = 0, Switch3 = 0 },
new State { Id = 2, Switch1 = 1, Switch2 = 0, Switch3 = 0 },
new State { Id = 3, Switch1 = 0, Switch2 = 1, Switch3 = 0 },
new State { Id = 4, Switch1 = 0, Switch2 = 1, Switch3 = 0 },
new State { Id = 5, Switch1 = 0, Switch2 = 1, Switch3 = 0 },
new State { Id = 6, Switch1 = 1, Switch2 = 1, Switch3 = 0 },
new State { Id = 7, Switch1 = 0, Switch2 = 0, Switch3 = 1 },
new State { Id = 8, Switch1 = 0, Switch2 = 0, Switch3 = 1 },
new State { Id = 9, Switch1 = 0, Switch2 = 0, Switch3 = 0 },
};
And ran the query, the list would contain your state transitions at items: 0, 2, 3, 6, 7, 9
I would do as follow:
class MyClass
{
int ID; //needs for recognize the message
int switch1; //0 or 1
int switch2; //0 or 1
int switch3; //0 or 1
public int Pattern
{
get { return switch1 + switch2 << 1 + switch3 << 2; }
}
}
Then it must be declared a dictionary with the previous-state messages:
Dictionary<int, int> _prevStates;
each cell has for key the ID, and for value the "Pattern" of the message.
At this point, let's suppose that the new incoming message stream is a list of MyClass:
IEnumerable<MyClass> incoming = ...
var changed = from msg in incoming
where _prevStates.ContainsKey(msg.ID) //what to do?
where _prevStates[msg.ID].Pattern != msg.Pattern
select msg;
Finally, you must update the dictionary with the changed patterns.
Cheers

Categories