Updating a row in a datatable during a foreach C# - c#

I'm looking for best practices for modifying a datatable while you are looping through said datatable.
I'm grabbing the max value in the datatables sequence line number column. In this example it's 25. I have a lot of zeroes in this Datatable and I'm going to find them one by one and change them to 25+1,26+1,27+1 etc etc. I'm wondering what would be the best practice of going about this without having to create another table and build a new table as I edit values of the row.
int maxSequenceNumber = Convert.ToInt32(dtNewOrderGuide.Compute("max([seqlinnum])", string.Empty));
foreach(DataRow row in dtNewOrderGuide.Rows)
{
if (row["seqlinnum"].ToString() == "0")
{
}
}
Example of my table
RowNumber | seqlinnum
1 | 1
2 | 10
3 | 15
4 | 25
5 | 0
6 | 0
7 | 0
8 | 0
9 | 0
10 | 0

as an alternative, using a traditional for loop over a foreach would mean not doing any data copying or anything and would likely run though the datatable faster
for(int i=0;i<table.Rows.Count;i++)
{
if (table.Rows[i]["seqlinnum"].ToString() == "0")
{
table.Rows[i]["seqlinnum"]=maxSequenceNumber; maxSequenceNumber++;
}
}

You can do this with Linq... may want to use an order why before the select if you don’t want to risk overwriting the sequence.
var query = td.Rows.Cast<DataRow>().Select((r,i)=>new {r,i});
foreach (var row in query)
{
row.r[“seqlinnum”]=row.i;
}

Related

how to check if a record exits in one table then it should ignore it in c#

i have two tables as follow in sql
Branches
ID | BranchID | GameTypeID | flag
1 | 55 | 111 | 1
2 | 16 | 235 | 0
Games
GameTypeID
123
456
111
235
458
what i am trying to achieve is that when Games is loaded it must check if the GameTypeID exits in the branch table for that ID and that the flag is 1. So for example if i pass BranchId 55 then from the Games list gametypeid 111 should be removed giving me the following list
Expected Outcome
Games
235
123
456
458
this is my code
GameLevel retVal = new GameLevel(GetGames(gameid, isdateroot, startdate, enddate, iscurrent, isdatesort, requestfrom));
var assignments =GetByBranchId(SessionManager.LoggedBranch.BranchIDb => b.Flag);
if (assignments.Any())
{
var gameTypes = assignments.Select(x => x.GameTypeId.ToString()).ToList();
retVal.Rows = retVal.Rows.Where(x => gameTypes.Contains(x.GameTypeID)).ToList();
}
return retVal;
so whats happening in the above is that when its passing the BranchID 55 its going and checking the flag but the problem is that when it finds that row its not ignoring the GametypeID 111 it ignores everything else and this is the result i get back
*current output*
Games
111
what is wrong with my code?
I think I see the issue. I'm going to walk through your code here so, if I make a bad assumption you can correct my
//1. This line gets an instance of a List<Games> (or something roughly like that)
GameLevel retVal = new GameLevel(GetGames(gameid, isdateroot, startdate, enddate, iscurrent, isdatesort, requestfrom));
//2. This line gets the GameTypeIds for the flagged Branch
var assignments =GetByBranchId(SessionManager.LoggedBranch.BranchIDb => b.Flag);
//3. self explanatory. 'If there is anything in the assignment variable'
if (assignments.Any())
{
//4. Get a list of GameTypeId values from assignments
var gameTypes = assignments.Select(x => x.GameTypeId.ToString()).ToList();
//5. Here's where I think you went wrong
//5. This line gets the Games where gameTypes contains the GameTypeId in retVal.
retVal.Rows = retVal.Rows.Where(x => gameTypes.Contains(x.GameTypeID)).ToList();
}
return retVal;
What you want are all the games in 'retVal' that are NOT included in 'gameTypes.GameTypeId'
and what you are actually returning is the opposite. You are returning all the games in 'retVal' that have a matching GameTypeId in 'gameTypes'
so...all you need to do is the opposite of what you're currently doing
change this line
retVal.Rows = retVal.Rows.Where(x => gameTypes.Contains(x.GameTypeID)).ToList();
into this
retVal.Rows = retVal.Rows.Where(x => !gameTypes.Contains(x.GameTypeID)).ToList();
All I did was add the 'not' operator and now you're returning the Games that DON'T match the flagged GameTypeId's

How to sum 2 columns within a row of datagridView

Hello guys? i'am working on Windows application form c# and I have 4 Columns in my datagridView, lets say i have 3 rows just like this
-------------------------------
|Grade1|Grade2|Average|Remarks|
|------|------|-------|-------|
| 85| 80| 82.5|PASSED |
| 76| 86| 81|PASSED |
| 75| 72| 73.5|FAILED |
-------------------------------
Now my question is it possible if i click a compute button it will compute each rows of the Column"Grade1" and Column"Grade2" the computation is
Grade1 + Grade2 = Average and Average = Average/2
if it's below 74 the remarks column automatically Have a "FAILED"
if it's above 75 the remarks column automatically Have a "PASSED"
Does anyone have a example code or a link that can help me to do this? Thank you so much!
you can enumerate thru all the rows by doing
foreach(DataGridViewRow row in dataGridView.Rows)
you can get or set the value of cells in that particular row by doing
row["column name"].Value
you can attach a click event to Button.Click (either in code by using .Click += handler or do it in the designer)
To assemble all those pieces and come up with a working solution will be your exercise. Good luck :)
private void CalculateButton_Click(object sender, EventArgs e)
{
foreach (DataGridViewRow row in dgvGrades.Rows)
{
if (decimal.TryParse(row.Cells["Grade1"]?.Value?.ToString(), out decimal Grade1)
&& decimal.TryParse(row.Cells["Grade2"]?.Value?.ToString(), out decimal Grade2))
{
var avg = (Grade1 + Grade2) / 2;
row.Cells["Average"].Value = avg;
if (avg < 74)
{
row.Cells["Remarks"].Value = "FAILED";
}
else
{
row.Cells["Remarks"].Value = "PASSED";
}
}
}
}
I would just add members to the class that is populating the array or list that is used to populate the grid. The getters for the average and pass/fail fields can handle the logic.

Best Algorithm to find intersection between 2 Intervals

I have a table in the database called Control:
Table structure:
Id | Name | MinValue (decimal) | MaxValue(decimal)
I have some restrictions on that table, one of it's restrictions is : no intersections.
Example : if the table has some values as follows:
row1 : 1 | Test1 | 1.3 | 2.5 //valid
row2 : 2 | Test2 | 3.3 | 4.5 // valid
row3 : 3 | Test3 | 5 | 6 // valid
Now if I want to add a new record, it must not intersect with any other row
Example:
row4 : 4 | Test4 | 5.1 | 10 //not valid since slot from 5 to 6 is reserved
row5 : 5 | Test5 | 1.0 | 1.4 // not valid since slot from 1.3 to 2.5 is reserved
I'm using this code, and it worked perfectly, but I wonder if there is a better solution and more efficient :
var allRows = db.Control.ToList();
var minValue = control.MinimumValue;
var maxValue = control.MaximumValue;
bool flag = true;
foreach(var row in allRows)
{
for(var i = minValue; i <= maxValue && flag ; i = decimal.Add( i , (decimal) 0.01))
{
if(i >= row.MinimumValue && i <= row.MaximumValue)
{
flag = false;
min = row.MinimumValue;
max = row.MaximumValue;
break;
}
}
}
if (flag)
{
//add
}
else
{
//intersection
}
Any suggestions ?
I think this is a O(LogN) issue...
Keep segments Ordered by their Start Value.
in a valid list s[i].end < s[i+1].start for any i
when inserting new segment, find it's position (the one that which start is closest (but lesser) than your new segment) call it i
if((seg[i-1].end < new.start) && (seg[i+1].start > new.end))
//OK to insert
else
// intersect
Let's assume this is the object you're trying to add :
var control = new Control()
{
Name = 'name',
MinValue = 5,
MaxValue = 6
};
You can do the following:
var biggerThanMinValue = db.Control.Count(x => x.MinValue >= control.MinValue) != 0;
var biggerThanMaxValue = db.Control.Count(x => x.MaxValue >= control.MaxValue) != 0;
if (!biggerThanMinValue && !biggerThanMinValue)
{
db.Control.Add(control); // or whatever your add operation is
}
By doing so you:
do NOT load the whole table in-memory -> performance gain terms of time, traffic and memory
let the database use it's data structures/algorithms to verify that the item can be added (the db should be able to optimize this request) -> another performance gain (cpu + time)
have clearer backend code
have less code to test
Edit: I suppose you could also ask the database to sort your table by min/max value and then make some validation (1 or 2 ifs), but the first approach is better, imo.

Non-boolean "truth table" creation

I have the following problem: I need to create a table, which is combination of values coming from sets. The cardinality of the elements in the set is unknown, and may vary from set to set, the domain of the values is unknown, and may as well vary from set to set. The elements in the set are non-negative, at least two elements are within a set.
Here follows an example:
SET_A = { 0, 1, 2 }
SET_B = { 0, 1 }
SET_C = { 0, 1 }
The result should contain the following rows (order is not a constraint):
TABLE:
| 0 0 0 |
| 0 0 1 |
| 0 1 0 |
| 0 1 1 |
| 1 0 0 |
| 1 0 1 |
| 1 1 0 |
| 1 1 1 |
| 2 0 0 |
| 2 0 1 |
| 2 1 0 |
| 2 1 1 |
Does anybody know which is the Mathematics behind this problem? I tried to look at Multiset problems, logic tables, combinatorics. Many of the definitions that I found have similarities to my problem, but I can't isolate anything in the literature that I have accessed so far. Once I have a reference definition I can think of coding it, but now I just got lost in recursive functions and terrible array-index games. Thanks.
EDIT: Question was proposed already at:
C# Permutation of an array of arraylists?
Edit: Sorry, had to run last evening. For arbitrary dimensionality you probably would have to use recursion. There's probably a way to do without it, but with recursion is most straightforward. The below is untested but should be about right.
IEnumerable<int[]> getRows(int[][] possibleColumnValues, int[] rowPrefix) {
if(possibleColumnValues.Any()) { //can't return early when using yield
var remainingColumns = possibleColumnValues.Skip(1).ToArray();
foreach(var val in possibleColumnValues.First()) {
var rowSoFar = rowPrefix.Concat(new[]{val}).ToArray();
yield return getRows(remainingColumns rowSoFar);
}
}
}
Usage:
getRows(new [][] {
new [] {0,1,2},
new [] {0,1},
new [] {0,1},
}, new int[0]);
The thing you look for is combinatorics. Also it doesn't really matter what is the domain of the elements in set. As long as you can enumerate them, the problem is the same as for numbers from 0 to the set cardinality.
To enumerate all options, have a vector of indices and after each iteration increment the first index. If it overflows, set to 0 and increment the second index, etc.
The task is to print permutations. You seem to dig deeper then it is. It has nothing to do with nature of elements.
The following is not written for efficiency (neither in space nor speed). The idea is to just get the basic algorithm across. I'll leave making this more space and time efficient up to you.
The basic idea is to recognize that all the combinations of n lists, is just all the combinations of n-1 lists with each element of the first list tacked on. It's a pretty straight-forward recursive function at that point.
public static IEnumerable<int[]> Permute( params IEnumerable<int>[] sets )
{
if( sets.Length == 0 ) yield break;
if( sets.Length == 1 )
{
foreach( var element in sets[0] ) yield return new[] { element };
yield break;
}
var first = sets.First();
var rest = Permute( sets.Skip( 1 ).ToArray() );
var elements = first.ToArray();
foreach( var permutation in rest )
{
foreach( var element in elements )
{
var result = new int[permutation.Length + 1];
result[0] = element;
Array.Copy( permutation, 0, result, 1, permutation.Length );
yield return result;
}
}
}

Creating a multi-layered matrix-ish Collection in C#

The setup
I have a List<Room>() which I get back from a service. The list refreshes every 10 seconds, and rooms get added and removed.
class Room
{
public int ID {get;set;}
}
My job
To display these rooms on the screen, I have a Matrix-like view of variable size.
Sometimes the matrix is 3 x 3 cells, other times it is 4 x 2 or 5 x 1.
I needed a way to "remember" which slot/cell a room has been placed in, so I thought a DataTable would give me that option.
To store the cells I use a DataTable, which has 3 Columns:
"Column" (int)
"Row" (int)
"Room" (Room)
So If I have a 2 x 4 matrix, it would look like this.
Column | Row | Room
-----------------------------
0 | 0 | rooms[0]
-----------------------------
1 | 0 | rooms[1]
-----------------------------
2 | 0 | rooms[2]
-----------------------------
0 | 1 | rooms[3]
-----------------------------
1 | 2 | rooms[4]
And so forth...
Once I have this DataTable I am then able to refresh the screen, knowing that each room will be displayed at the position it was before. This can probably be achieved in a smarter way.
The problem
Now I need to enumerate the List<Room> and fill the matrix/DataTable.
If I have more rooms than cells, then I need to start at position 0,0 again (like adding a new matrix as a layer), until all rooms have been assigned a cell.
The approach so far
I have tried a few for(...) loops that look like:
int totalTiles = area.TileColumns * area.TileRows;
int totalLayers = (int)Math.Ceiling((double)area.Rooms.Count / totalTiles);
for (int i = 0; i < totalLayers; i++)
{
for (int j = 0; j < area.TileRows; j++)
{
for (int k = 0; k < area.TileColumns; k++)
{
// This is going nowhere :-(
}
}
}
In my brain
When I first came across this problem, I immediately thought: "Nothing a simple LINQ query won't fix!". And then I bricked ...
What would be the most efficient / best performing approach to fill this matrix?
Without being able to make assumptions, like will the row/columns change at runtime, I would have to say just make it completely dynamic.
class RoomStorage
{
public Room room {get;set;}
public int layer {get;set;}
public int row {get;set;}
public int col {get;set;}
}
var matrix=new List<RoomStorage>();
Then you can things like:
var newRooms=new List<Room>(); // Get from service
//Remove rooms no longer in use
var matrix=matrix.Where(m=>newRooms.Select(nr=>nr.ID).Contains(m.Room.ID));
//Find rooms we need to add (Optionally use Exclude for faster perf)
var roomsToAdd=newRooms.Where(r=>matrix.Select(m=>m.Room.ID).Contains(r.ID));
var maxLayer=matrix.Max(m=>m.layer);
var rows = ?
var cols = ?
var positions=Enumerable
.Range(0,maxLayer+1)
.SelectMany(layer=>
Enumerable
.Range(0,rows)
.SelectMany(row=>
Enumerable
.Range(0,cols)
.Select(col=>new {layer,row,col})));
Then you can use positions, left joining it to matrix for display purposes, or finding the first empty position.

Categories

Resources