Taking the first N number of rows is pretty straightforward and works well with
var topPvtTbl = new TopPivotTable(runningPvtTbl, 3, 99);
topPvtTbl.IncludeOtherGroups = false;
Is there an inverse? My use case is that the data is returning dates in ascending order on the rows and instead of taking the first 3 dates, I want the last 3 dates. I don't see a BottomPivotTable option.
You can achieve what you want in the following way:
configure base PivotTable class to order axis with dates in reverse order (descending)
apply TopPivotTable wrapper to select only first 3 dates (= so they will be actually last 3 days)
reverse axis keys with Array.Reverse. For example, if dates are columns: Array.Reverse(topPvtTbl.ColumnKeys);
-- update --
This approach will not work if underlying table-related calculation relies on the concrete axis order (like RunningValuePivotTable). Alternatively, you can implement your own IPivotTable wrapper that takes last N items. For example:
public class LastNColumnsPivotTable : IPivotTable {
IPivotTable basePvtTbl;
public LastNColumnsPivotTable(IPivotTable pvtTbl, int lastN) {
basePvtTbl = pvtTbl;
if (basePvtTbl.ColumnKeys.Length>lastN) {
lastColumnKeys = basePvtTbl.ColumnKeys.Skip(basePvtTbl.ColumnKeys.Length - lastN).ToArray();
} else {
lastColumnKeys = basePvtTbl.ColumnKeys;
}
}
public string[] Columns { get { return basePvtTbl.Columns; } }
public string[] Rows { get { return basePvtTbl.Rows; } }
ValueKey[] lastColumnKeys;
public ValueKey[] ColumnKeys { get { return lastColumnKeys; } }
public ValueKey[] RowKeys { get { return basePvtTbl.RowKeys; } }
public IPivotData PivotData { get { return basePvtTbl.PivotData; } }
public IAggregator GetValue(ValueKey rowKey, ValueKey colKey) {
return basePvtTbl.GetValue(rowKey, colKey);
}
}
Related
I'm creating a program to generate schematics based off of user input. This has to be done dynamically/by hand due to the sheer volume of different possibilities (6.8M, growing exponentially). Right now I'm working on importing some data via CSV.
Example data:
Type,TIN_pos,TIN_ID,Desc
Elect, 0, X, Manual Regulator
Elect, 0, A, Electronic Regulator
Import code:
List<TIN_Fields> values = File.ReadAllLines("C:\\Users\\User\\Desktop\\Visual Basic\\CSV_Test_1.csv")
.Skip(1)
.Select(v => TIN_Fields.FromCsv(v))
.ToList();
public class TIN_Fields
{
public string Type;
public int TIN_pos;
public string TIN_ID;
public string Desc;
public static TIN_Fields FromCsv(string csvLine)
{
string[] values = csvLine.Split(',');
TIN_Fields _Fields = new TIN_Fields();
_Fields.Type = Convert.ToString(values[0]);
_Fields.TIN_pos = Convert.ToInt16(values[1]);
_Fields.TIN_ID = Convert.ToString(values[2]);
_Fields.Desc = Convert.ToString(values[3]);
return _Fields;
}
}
Once that data is Imported, I need to do two things with it,
display the raw csv data in a ListView table, just so users can see if anything in the list needs updating.
be able to compare the items in the list to various characters in a 10-digit hexadecimal code, and spit out some results.
First and foremost, i need to run through the list that was created with the above code, make sure that:
TIN_pos value = 0
because that is the character position of the input box.
Then, with the remaining options, look for the character represented in the input in the TIN_ID field.
Once found, it should then output the Desc field.
Everywhere I have looked says to use foreach, but that requires the array name, which is the part that is confusing me. I've tried filling in basically all of the variables in the FromCSV Method and usually get an error that the class doesn't have a definition.
to hopefully clear up confusion with my explanation, here is the code I created that does the same thing, but with the CSV data hard coded into it, using switch cases and if statements.
public partial class Form1 : Form
{
public string Model_Chassis;
public string Model_Test_Type;
public int ChannelNumberVar => Convert.ToInt32(TextBox_TIN[2]);
public string Tester_Type_Selector;
public string TextBox_TIN
{
get { return TIN_Entry_TextBox.Text; }
set { TIN_Entry_TextBox.Text = value; }
}
public string Model_Data_D
{
get { return Model_Data.Text; }
set { Model_Data.Text = value; }
}
public Form1()
{
InitializeComponent();
}
//Method grabs TIN Box data and decodes it to model information.
public void Model_Select()
{
//Picks Model Chassis
switch (char.ToUpper(TextBox_TIN[0]))
{
case 'H':
{
Model_Chassis = Coding.Model1.description;
}
break;
default:
{
Model_Data_D = "INVALID TIN";
}
break;
}
//Picks Test Type
switch (char.ToUpper(TextBox_TIN[3]))
{
case '0':
{
Model_Test_Type = Test_Types.TT_PD.TT_tt;
}
break;
case '1':
{
Model_Test_Type = Test_Types.TT_PV.TT_tt;
}
break;
default:
{
Model_Test_Type = "";
}
break;
}
//Puts chassis and Test Type together
if (Model_Data_D.Equals("INVALID TIN"))
{
;
}
else if (char.ToUpper(TextBox_TIN[2]).Equals(Coding.Num_Chan_1_2.tin_id))
{
Model_Data_D = $"{Model_Chassis}-{Model_Test_Type}";
}
else
{
Model_Data_D = $"{Model_Chassis}-{TextBox_TIN[2]}{Model_Test_Type}";
}
}
public class Coding
{
public char tin_id;
public string description;
public Coding(char TIN_ID, string Desc)
{
tin_id = TIN_ID;
description = Desc;
}
public static Coding Model1 = new Coding('H', "Model1");
public static Coding Num_Chan_1_2 = new Coding('X', "Single Channel");
public static Coding Elect_Reg_F_1 = new Coding('X', "Manual Regulator");
}
}
INPUT:
HXX0X
OUTPUT
Model1-PD
Thanks in advance for the help!
You're asking quite a few questions, and providing a lot of extra details in here, but for this:
"First and foremost, i need to run through the list that was created with the above code, make sure that:
TIN_pos value = 0
because that is the character position of the input box."
(seeing as you say you need to do this 'first and foremost').
In your FromCsv method, check the value as you create the record, and throw an error if it is invalid. Like this:
public static TIN_Fields FromCsv(string csvLine)
{
string[] values = csvLine.Split(',');
TIN_Fields _Fields = new TIN_Fields();
_Fields.Type = Convert.ToString(values[0]);
_Fields.TIN_pos = Convert.ToInt16(values[1]);
if(_Fields.TIN_pos != 0){
throw new Exception("TIN_pos must be 0");
}
_Fields.TIN_ID = Convert.ToString(values[2]);
_Fields.Desc = Convert.ToString(values[3]);
return _Fields;
}
Assuming you've read in your CSV correctly, which it seems you have, then selecting the appropriate TIN from the list is a simple LINQ statement. The following code assumes that TIN IDs are unique and only a single character in length.
static void Main(string[] args)
{
string testCsv = #"C:\Users\User\Desktop\Visual Basic\CSV_Test_1.csv";
List<TIN_Fields> values = File.ReadAllLines(testCsv)
.Skip(1)
.Select(v => TIN_Fields.FromCsv(v))
.ToList();
// Simulates input received from form
string input = "HXX0X";
TIN_Fields selectedTIN = values.First(x => x.TIN_ID == Convert.ToString(input[0]));
// Insert the description as needed in your ouput.
string output = $"{ selectedTIN.Desc }-";
}
Hopefully that answers another part of the problem. The Convert.ToString() is required because the output of input[0] is a char.
Hy guys!
I have a project where I need to find out if you can make gold from iron. The way it is is that each material is represented with a number from 1-200 and a catalisator which makes one material from an other with letters (A-Z). They experiment and store the records in a txt files. Each records looks like this: material1 catalisator material2. So this is basically a graph where every material is a vertex and every catalisator is an edge. The task is to read the txt files and create an other one with the necessary edges from iron(represented with 1) to gold(represented with 0). My current state is that I have a class called Beeolvaso:
class Beolvaso
{
public int anyag1;
public int anyag2;
public string katalizator;
public bool tovabbMehete;
public int Anyag1
{
get
{
return anyag1;
}
set
{
anyag1 = value;
}
}
public bool TovabbMehete
{
get
{
return tovabbMehete;
}
set
{
tovabbMehete = value;
}
}
public int Anyag2
{
get
{
return anyag2;
}
set
{
anyag2 = value;
}
}
public string Katalizator
{
get
{
return katalizator;
}
set
{
katalizator = value;
}
}
public Beolvaso(int anyag1, string katalizator, int anyag2, bool tovabbMehete)
{
this.anyag1 = anyag1;
this.anyag2 = anyag2;
this.katalizator = katalizator;
this.tovabbMehete = tovabbMehete;
}
it basiacally stores material1 material2 catalisator and a boolean which tells us if we can continoue from material2 to an other material or not.
I have an array containing serials of these Beolvaso classes I created that stores the data from the text in a structure and I need an algorithm that iterates through the records and return all the possible routes(serial of catalisators) from 1(iron) to 0(gold). I looked up different graph searches like DFS or BFS but I need an algorith specifically for that case. Can you guys help me out?
Why I'm doing this:
So I'm trying to make an application for a game called clash royale, after winning the games there you get a "random" chest, which is actually not random... When you create your account you get a digit assigned to you from 0 to 239, and after that it follows a pattern for the chest drops. The applciation I'm making would take a user's entries and compare it to the pattern, thus being able to predict how soon the next chests of a higher quality would drop.
The help I need with the code:
Is it possible to make an array kind of... loop within itself.. So for example when going through the array in a loop, if "i" is 239, then adding +1 would take it back to the beginning, or #0 (239 not necessarily being the limit).
The class (and it's container that I want to loop):
class Chest
{
public int ID { get; set; }
public string Type { get; set; }
public Chest()
{
}
public Chest(int id, string type)
{
ID = id;
Type = type;
}
}
class ChestContainer
{
private Chest[] ChestList = new Chest[240];
public int Count { get; set; }
public ChestContainer(int size)
{
ChestList = new Chest[size];
}
public void Add(Chest chest)
{
ChestList[Count++] = chest;
}
public Chest Get(int index)
{
return ChestList[index];
}
}
Also wouldn't mind any tips to improve my class / container class, at the moment this is what I've been doing for pretty much my entire "career" as this is what we were thought in uni (minus the string override for the class).
You could use Modulo % in order to get a loop kind of thing.
If you replace the Container.Add method with the one below, the index will be "reset" (for lack of better words).
public void Add(Chest chest)
{
ChestList[Count++%(ChestList.Length)] = chest;
}
After updating the method, if you want an example, you can try the code below:
var container = new ChestContainer(240);
for (int i = 0; i < 1000; i++)
container.Add(new Chest(i, $"{i}"));
Edit In order to have the Get method working as well, modifying it as mentioned below will ensure your container works as expected:
public Chest Get(int index)
{
return ChestList[index%(ChestList.Length)];
}
To test it out, you can use the code below:
var container = new ChestContainer(240);
for (int i = 0; i < 1000; i++)
{
container.Add(new Chest(i, $"{i}"));
var value = container.Get(i);
}
You can overload the [] operator to define it's behaviour.
Something like this:
public static Chest operator [] (int index) {
return ChestList[index%240];
}
public Chest Get(int index)
{
return ChestList[index%240]; //put your limit here
}
How it works: % is the modulo operator.
It returns the remainder of a devision.
Example:
5/2 = 2, remaining 1
=> 5%2 = 1
In your case, when numbers higher than 239 are entered, with modulo it just wraps around.
i have a List which get's and set's data from/to my class "Type" after a specific condition is fulfilled i want to clear all the variables value's that have been gathered here's my code
List<Type> Win = new List<Type>();
void Check(int a)
{
if (a>10)
{
Win.Add(new Type() { Power = 10 + a * 100, Current = 1 });
}
if(a<10)
{
Win.Add(new Type() { Power = 10 + a * 100, Current = 1 });
}
}
My class:
public class Type
{
public int Power { get; set; }
public int Current { get; set; }
}
And like this it will always enter the 2 if's at least once because I'm giving him a parameter "a" and a will change let's say 5 times and it will get a lot of different values.How can i clear the entire "Type.Power" and "Type.Current" variables or just clear the entire list "Win" ?
To empty the entire list, you can use .Clear().
Win.Clear();
To reset all instances of `Type.Power' and 'Type.Current' per instance in your list, you would need to iterate the list and update the members to their default value 0.
Win.ForEach(x =>
{
x.Power = 0;
x.Current = 0;
});
I am trying to sort the data in gridview
everything is working fine but numeric column(Marks) taking sorting for 1st number only
Code:
protected void gvTrHty_Sorting(object sender, GridViewSortEventArgs e)
{
try
{
this.gviewSorting(e.SortExpression);
}
catch (Exception ex)
{
string arg_15_0 = ex.Message;
}
}
private void gviewSorting(string strSortExp)
{
if (this.ViewState["dvTrain"] == null)
{
DataSet dataSet = this.BindTraining();
dv = dataSet.Tables[0].DefaultView;
}
else
{
DataSet dataSet2 = (DataSet)this.ViewState["dvTrain"];
TrainingHistory.dv = dataSet2.Tables[0].DefaultView;
}
if (TrainingHistory.sortorder)
{
TrainingHistory.sortorder = false;
TrainingHistory.dv.Sort = strSortExp + " DESC";
}
else
{
TrainingHistory.sortorder = true;
TrainingHistory.dv.Sort = strSortExp;
}
this.BindData(TrainingHistory.dv);
}
If I have values in Mark(column) in gridview
Marks----> When I click this for sorting it's taking Marks
1 1
8 1st number only sorted ---> 12
40 21
12 40
21 8
It is treating your "numerical" data as a string and doing the sort against this string value, thus "40" is less than "8".
Your options are:
Put leading zeroes on the numeric field values, which is probably a no-go for obvious reasons, this would allow the existing sort to work correctly. I suppose you could temporarily put leading zeroes and then rip them out after the sort, but this sounds like a headache.
Implement your own sorting logic, like this:
public sealed class GenericComparer<T> : IComparer<T>
{
public enum SortOrder
{
Ascending = 0,
Descending = 1
}
private string sortColumn;
private SortOrder sortingOrder;
public string SortColumn
{
get
{
return this.sortColumn;
}
}
public SortOrder SortingOrder
{
get
{
return this.sortingOrder;
}
}
public GenericComparer(string theSortColumn, SortOrder theSortingOrder)
{
this.sortColumn = theSortColumn;
this.sortingOrder = theSortingOrder;
}
public int Compare(T x, T y)
{
PropertyInfo thePropertyInfo = typeof(T).GetProperty(this.sortColumn);
IComparable object1 = (IComparable)thePropertyInfo.GetValue(x, null);
IComparable object2 = (IComparable)thePropertyInfo.GetValue(y, null);
if (this.sortingOrder == SortOrder.Ascending)
{
return object1.CompareTo(object2);
}
else
{
return object2.CompareTo(object1);
}
}
}
Now in your call to .Sort() method, you pass a new instance of this helper class (passing it the column you want to sort by and the direction you want to sort - ascending or descending).
Since the comparer logic above uses generics, you can pass whatever type you want to sort by (i.e. int, DateTime, or even entire domain objects).