Return results from data table in a sequence using linq - linq

I'm fetching rows from excel sheet in my application that holds attendance records from the bio metric machine. In order to get the best result i have to remove the redundant data. For that I have to manage check in and checkout timings at regular intervals. For instance, First check in time for entering, and then checkout time for lunch, then again check in for returning back, and last check out for going home. Meanwhile the rows in excel contains multiple check ins and check outs as the employee tends to do more that once for both.
I have managed to get records from excel and added to data table. Now for the sequence and sorting part I'm struggling to achieve my desired result. Below is my code.
protected void btnSaveAttendance_Click(object sender, EventArgs e)
{
try
{
if (FileUpload1.HasFile && Path.GetExtension(FileUpload1.FileName) == ".xls")
{
using (var excel = new OfficeOpenXml.ExcelPackage(FileUpload1.PostedFile.InputStream))
{
var tbl = new DataTable();
var ws = excel.Workbook.Worksheets.First();
var hasHeader = true; // adjust accordingly
// add DataColumns to DataTable
foreach (var firstRowCell in ws.Cells[1, 1, 1, ws.Dimension.End.Column])
tbl.Columns.Add(hasHeader ? firstRowCell.Text
: String.Format("Column {0}", firstRowCell.Start.Column));
// add DataRows to DataTable
int startRow = hasHeader ? 2 : 1;
for (int rowNum = startRow; rowNum <= ws.Dimension.End.Row; rowNum++)
{
var wsRow = ws.Cells[rowNum, 1, rowNum, ws.Dimension.End.Column];
DataRow row = tbl.NewRow();
foreach (var cell in wsRow)
row[cell.Start.Column - 1] = cell.Text;
tbl.Rows.Add(row);
}
var distinctNames = (from row in tbl.AsEnumerable()
select row.Field<string>("Employee Code")).Distinct();
DataRow[] dataRows = tbl.Select().OrderBy(u => u["Employee Code"]).ToArray();
var ss = dataRows.Where(p => p.Field<string>("Employee Code") == "55").ToArray();
}
}
}
catch (Exception ex) { }
}
The result i'm getting is:
Employee Code Employee Name Date Time In / Out
55 Alex 12/27/2018 8:59 IN
55 Alex 12/27/2018 8:59 IN
55 Alex 12/27/2018 13:00 OUT
55 Alex 12/27/2018 13:00 OUT
55 Alex 12/27/2018 13:48 IN
55 Alex 12/27/2018 13:49 IN
55 Alex 12/27/2018 18:08 OUT
And I want to have first In and then out and then in and then out. This would iterate four times to generate the result.
Expected result is:
Employee Code Employee Name Date Time In / Out
55 Alex 12/27/2018 8:59 IN
55 Alex 12/27/2018 13:00 OUT
55 Alex 12/27/2018 13:48 IN
55 Alex 12/27/2018 18:08 OUT

Can you try to do groupby in the result like below
ss=ss.GroupBy(x=>x.DateTime).ToArray();
Build a logic, if your result have 2 successive In/Out as a sample like below.
Here In I considered as field name
var tt;
for(int i=0;i<ss.Count();i++)
{
if(ss[i].In=="In" && (tt!=null || tt.LastOrDefault().In!="In"))
tt=ss[i];
else if(ss[i].In=="Out" && (tt!=null || tt.LastOrDefault().In!="Out"))
tt=ss[i];
}

Related

Deviding dates into periods by linq c#

I have a datatable contains three columns (Names and Dates)
Names Dates amount
----------------------------------
John 01/01/2019 5
John 02/01/2019 10
John 04/01/2019 5
John 05/01/2019 4
Adam 01/01/2019 5
Adam 03/01/2019 5
Adam 04/01/2019 5
I need to check missed days and make periods
I expect output like
Names Fr To amount
John 01/01/2019 02/01/2019 15
John 04/01/2019 05/01/2019 9
Adam 01/01/2019 01/01/2019 5
Adam 03/01/2019 04/01/2019 10
If you divide the problem into sub-parts then it becomes a lot simpler.
Make pairs from the entries of the datatable.
Now make groups based on Name.
On this groups check which group has the time difference of 1 month.
Project this groups using a foreach loop.
Now the code,
public static class Program
{
static int CountNumberOfMonths(DateTime date1, DateTime date2) => (date2.Month - date1.Month) + 12 * (date2.Year - date1.Year);
static void Main(string[] args)
{
DataTable table = new DataTable();
table.Columns.Add("Name", typeof(string));
table.Columns.Add("Dates", typeof(DateTime));
table.Columns.Add("Amount", typeof(int));
table.Rows.Add("John", new DateTime(2019, 1, 1), 5);
table.Rows.Add("John", new DateTime(2019, 2, 1), 10);
table.Rows.Add("John", new DateTime(2019, 4, 1), 5);
table.Rows.Add("John", new DateTime(2019, 5, 1), 4);
table.Rows.Add("Adam", new DateTime(2019, 1, 1), 5);
table.Rows.Add("Adam", new DateTime(2019, 3, 1), 5);
table.Rows.Add("Adam", new DateTime(2019, 4, 1), 5);
var enumeratedDatatable = table.AsEnumerable();
var filteredData = enumeratedDatatable
.Zip(enumeratedDatatable.Skip(1), Tuple.Create)
.GroupBy(x => x.Item1.Field<string>("Name"))
.Select(x => x.Where(y =>
{
int numMonths = CountNumberOfMonths(y.Item1.Field<DateTime>("Dates"), y.Item2.Field<DateTime>("Dates"));
return numMonths > 0 && numMonths == 1;
}));
DataTable result = new DataTable();
result.Columns.Add("Name", typeof(string));
result.Columns.Add("From", typeof(DateTime));
result.Columns.Add("Sum", typeof(DateTime));
result.Columns.Add("Amount", typeof(int));
foreach (var item in filteredData)
{
string name = item.ElementAt(0).Item1.Field<string>("Name");
foreach (var innerItem in item)
{
int sumAmount = innerItem.Item1.Field<int>("Amount") + innerItem.Item2.Field<int>("Amount");
DateTime from = innerItem.Item1.Field<DateTime>("Dates");
DateTime to = innerItem.Item2.Field<DateTime>("Dates");
result.Rows.Add(name, from, to, sumAmount);
}
}
// Printing the results to standard output
foreach (DataRow row in result.Rows)
{
string rowItem = string.Join("\t", row.ItemArray);
Console.WriteLine(rowItem);
}
}
}
Outputting:
John 01/01/2019 00:00:00 02/01/2019 00:00:00 15
John 04/01/2019 00:00:00 05/01/2019 00:00:00 9
Adam 03/01/2019 00:00:00 04/01/2019 00:00:00 10

How to solve compare two datatables linq to sql error?

I have two datatables and I need to compare one columns and delete some results .(One Columns=ID)
I use datatable 1 and datatable 2 linq expression.I want to database3.
Common area ise ID:83,21
datatable 1
StudentID ClassNumber No
83 65 1
21 28 15
35 56 87
datatable 2
StudentID BranchNumber
83 3
21 2
datatable 3
StudentID ClassNumber
83 65
21 28
I write this query
public static DataTable Student(Datatable ds,Datatable dc)
{
DataTable StudentDatabaseID1= new DataTable();
DataTable StudentDatabaseID2= new DataTable();
var result=from a in StudentDatabaseID1.AsEnumerable()
join b in StudentDatabaseID2.AsEnumerable()
on a.Field<int>("StudentID") equals b.Field<int>("StudentID")
select
{
StudentID=a.Field<int>("StudentID"),
ClassNumber=a.Field<int>("ClassNumber"),
}
}
I think that you haven't data in StudentDatabaseID1 and StudentDatabaseID2 because they are new variables, maybe you have to use Datatable ds,Datatable dc ???, check it, code works fine like next example:
CODE (this is for LinqPad but you can re-use in your code):
void Main()
{
// Build data
DataTable dt1 = new DataTable();
dt1.Clear();
dt1.Columns.Add("StudentId", typeof(Int32));
dt1.Columns.Add("ClassNumber", typeof(Int32));
dt1.Columns.Add("No", typeof(Int32));
DataRow row1 = dt1.NewRow();
row1["StudentId"] = 83;
row1["ClassNumber"] = 65;
row1["No"] = 1;
dt1.Rows.Add(row1);
row1 = dt1.NewRow();
row1["StudentId"] = 21;
row1["ClassNumber"] = 28;
row1["No"] = 15;
dt1.Rows.Add(row1);
row1 = dt1.NewRow();
row1["StudentId"] = 35;
row1["ClassNumber"] = 56;
row1["No"] = 87;
dt1.Rows.Add(row1);
DataTable dt2 = new DataTable();
dt2.Clear();
dt2.Columns.Add("StudentId", typeof(Int32));
dt2.Columns.Add("BranchNumber", typeof(Int32));
DataRow row2 = dt2.NewRow();
row2["StudentId"] = 83;
row2["BranchNumber"] = 3;
dt2.Rows.Add(row2);
row2 = dt2.NewRow();
row2["StudentId"] = 21;
row2["BranchNumber"] = 2;
dt2.Rows.Add(row2);
// Do query
var result =
from a in dt1.AsEnumerable()
join b in dt2.AsEnumerable() on a.Field<int>("StudentID") equals b.Field<int>("StudentID")
select new {
StudentID=a.Field<int>("StudentID"),
ClassNumber=a.Field<int>("ClassNumber"),
};
// Print result
result.Dump();
}
RESULT

advice to make my below Pig code simple

Here is my code and I do two group all operations and my code works. My purpose is to generate all student unique user count with their total scores, student located in CA unique user count. Wondering if good advice to make my code simple to use only one group operation, or any constructive ideas to make code simple, for example using only one FOREACH operation? Thanks.
student_all = group student all;
student_all_summary = FOREACH student_all GENERATE COUNT_STAR(student) as uu_count, SUM(student.mathScore) as count1,SUM(student.verbScore) as count2;
student_CA = filter student by LID==1;
student_CA_all = group student_CA all;
student_CA_all_summary = FOREACH student_CA_all GENERATE COUNT_STAR(student_CA);
Sample input (student ID, location ID, mathScore, verbScore),
1 1 10 20
2 1 20 30
3 1 30 40
4 2 30 50
5 2 30 50
6 3 30 50
Sample output (unique user, unique user in CA, sum of mathScore of all students, sum of verb Score of all students),
7 3 150 240
thanks in advance,
Lin
You might be looking for this.
data = load '/tmp/temp.csv' USING PigStorage(' ') as (sid:int,lid:int, ms:int, vs:int);
gdata = group data all;
result = foreach gdata {
student_CA = filter data by lid == 1;
student_CA_sum = SUM( student_CA.sid ) ;
student_CA_count = COUNT( student_CA.sid ) ;
mathScore = SUM(data.ms);
verbScore = SUM(data.vs);
GENERATE student_CA_sum as student_CA_sum, student_CA_count as student_CA_count, mathScore as mathScore, verbScore as verbScore;
};
Output is:
grunt> dump result
(6,3,150,240)
grunt> describe result
result: {student_CA_sum: long,student_CA_count: long,mathScore: long,verbScore: long}
first load the file(student)in hadoop file system. The perform the below action.
split student into student_CA if locationId == 1, student_Other if locationId != 1;
student_CA_all = group student_CA all;
student_CA_all_summary = FOREACH student_CA_all GENERATE COUNT_STAR(student_CA) as uu_count,COUNT_STAR(student_CA)as locationCACount, SUM(student_CA.mathScore) as mScoreCount,SUM(student_CA.verbScore) as vScoreCount;
student_Other_all = group student_Other all;
student_Other_all_summary = FOREACH student_Other_all GENERATE COUNT_STAR(student_Other) as uu_count,0 as locationOtherCount:long, SUM(student_Other.mathScore) as mScoreCount,SUM(student_Other.verbScore) as vScoreCount;
student_CAandOther_all_summary = UNION student_CA_all_summary, student_Other_all_summary;
student_summary_all = group student_CAandOther_all_summary all;
student_summary = foreach student_summary_all generate SUM(student_CAandOther_all_summary.uu_count) as studentIdCount, SUM(student_CAandOther_all_summary.locationCACount) as locationCount, SUM(student_CAandOther_all_summary.mScoreCount) as mathScoreCount , SUM(student_CAandOther_all_summary.vScoreCount) as verbScoreCount;
output:
dump student_summary;
(6,3,150,240)
Hope this helps :)
While solving your problem, I also encountered an issue with PIG. I assume it is because of improper exception handling done in UNION command. Actually, it can hang you command line prompt, if you execute that command, without proper error message. If you want I can share you the snippet for that.
The answer accepted has an logical error.
Try to have the below input file
1 1 10 20
2 1 20 30
3 1 30 40
4 2 30 50
5 2 30 50
6 3 30 50
7 1 10 10
The output will be
(13,4,160,250)
The output should be
(7,4.170,260)
I have modified the script to work correct.
data = load '/tmp/temp.csv' USING PigStorage(' ') as (sid:int,lid:int, ms:int, vs:int);
gdata = group data all;
result = foreach gdata {
student_CA_sum = COUNT( data.sid ) ;
student_CA = filter data by lid == 1;
student_CA_count = COUNT( student_CA.sid ) ;
mathScore = SUM(data.ms);
verbScore = SUM(data.vs);
GENERATE student_CA_sum as student_CA_sum, student_CA_count as student_CA_count, mathScore as mathScore, verbScore as verbScore;
};
Output
(7,4,160,250)

Xpages view string type ratio

I have a view with 2 columns, both type of String. One is always "08:00" and one depends on the user input. It could be 02:30 or 13:45, etc...
I want to convert all the column of 08:00's and all the other column of values, add them together and then divide the total...
Example:
Column 1 | Column 2
02:50 | 08:00
05:15 | 08:00
15:25 | 08:00
03:15 | 08:00
It would be something like:(~26)/(8*4)=~0.8%.
It's a timekeeping application. I have the normal-time of 8 hours and the time the employee worked, and I want to add a button that will calculate the ratio between the 2 columns.
Thank you,
Florin
This is the code I used to calculate the ration between 2 columns of strings:
var vec:NotesViewEntryCollection = viewSearch.getAllEntries();
var c = vec.getCount()
var data = #DbColumn(#DbName(),"vwSearch",4);
var totalH = 0;
var totalM = 0;
for(var i=0;i<c;i++){
var str = data[i].toString();
var a = str.split(":",2)[0];
var b = str.split(":",2)[1];
var hour = parseInt(a);
var minutes = parseInt(b);
totalH += hour;
totalM += minutes;
if(totalM >= 60)
{
totalH++;
totalM-=60;
}
}
var h_necesare = c*8;
getComponent("h_lucrate").setValue(totalH+" ore, si "+totalM+" minute.");
getComponent("h_necesare").setValue(h_necesare);
getComponent("raport").setValue(totalH-h_necesare);

LINQ to SQL array always returns first item?

i am using LINQ to SQL. My Database has 3 columns Ref, Due_amount, Due_Date.
Data may look like this, for example.
10 02/08/2009 00:00:00 175.0000
10 02/09/2009 00:00:00 175.0000
10 02/10/2009 00:00:00 175.0000
10 02/11/2009 00:00:00 175.0000
10 02/12/2009 00:00:00 175.0000
10 02/01/2010 00:00:00 175.0000
My code below, returns 6 elements and works, however the Date is always 02/08/2009? if i say change row 2's amount to 150.0000 it then returns the correct date of 02/09/2009?
Any ideas?
private static void PopulateInstalments(string Ref, ResponseMessage responseMsg)
{
using (DAO dbContext = new DAO())
{
IEnumerable<profile> instalments = (from instalment in dbContext.profile
where instalment.ref == Ref
select instalment);
foreach (profile instalment in instalments)
{
if (responseMsg.Instalments == null)
responseMsg.Instalments = new ArrayOfInstalments();
Instalment tempInstalment = new Instalment();
tempInstalment.DueAmount = instalment.Due_amount;
tempInstalment.DueDate = instalment.Due_date == null ? "" : instalment.Due_date.ToString();
responseMsg.Instalments.Add(tempInstalment);
}
}
}
Thanks
Richard
ensure primary key column is set in source (SQL Server Database in this case)

Resources