Please refer to this sample data:
# |IDNum |Date |data |SomeDate |TranCode
1|888888| 12/16/10|aaaaa| |a10
2|888888| 12/16/10|bbbbb| 11/16/15|a8
3|888888| 12/16/10|ccccc| |a11
4|888888| 11/16/10|aaaaa| |a6
5|888888| 11/16/10|bbbbb| |a5
6|888888| 11/16/10|ccccc| 10/16/15|a9
7|888888| 11/16/10|aaaaa| |a11
8|888888| 11/15/10|bbbbb| |a3
9|888888| 10/16/10|ccccc| |a6
10|888888| 10/16/10|aaaaa| |a5
11|888888| 10/16/10|bbbbb| 09/16/15|a9
12|888888| 10/16/10|ccccc| |a11
13|888888| 09/16/10|aaaaa| |a6
14|888888| 09/16/10|bbbbb| 08/16/15|a5
15|888888| 09/16/10|ccccc| |a9
16|111111| 03/02/15|aaaaa| |a9
17|111111| 02/27/15|bbbbb| 12/01/15|a6
18|111111| 02/10/15|ccccc| |a1
19|111111| 02/01/15|aaaaa| |a10
20|111111| 02/01/15|bbbbb| 11/01/15|a9
21|111111| 01/05/15|ccccc| |a10
22|111111| 01/05/15|aaaaa| 10/01/15|a9
23|111111| 12/31/14|bbbbb| |a12
24|111111| 12/30/14|ccccc| |a2
25|111111| 12/01/14|aaaaa| |a6
26|111111| 12/01/14|bbbbb| 10/01/15|a10
I have the above data stored as a list delimited by pipes and sorted by Date descending. I would need the "SomeDate" field to populate using the last date available in the row for that particular IDNumber.
So for example:
Row 1 should show a date of 11/16/15.
Row 3:5 should show a date of 10/16/15.
Row 7:10 should show a date of 09/16/15
Row 15 should show no date since there is no preceding date for that IDNum.
Row 16 should show a date of 12/01/15
Any logic recommendations would be much appreciated.
EDIT: To clarify - The data posted above is currently stored in a list. What I need help with is coming up with logic of how to solve my problem.
Here is a full writeup of how to solve this issue. Note that I put the sample data into C:\test\sample.txt for ease of use.
public class FileData
{
public string ID { get; set; }
public string IDNum { get; set; }
public string Date { get; set; }
public string Data { get; set; }
public string SomeDate { get; set; }
public string TranCode { get; set; }
}
public class ReadFile
{
public string SampleFile = #"C:\test\sample.txt";
public ReadFile()
{
StreamReader reader = new StreamReader(SampleFile);
string sampleFile = reader.ReadToEnd();
reader.Close();
string[] lines = sampleFile.Split(new string[] { "\r\n" }, StringSplitOptions.RemoveEmptyEntries);
string previousDate = "";
List<FileData> fileDatas = new List<FileData>();
for (int i = lines.Length - 1; i >= 0; i--)
{
FileData data = new FileData();
string[] columns = lines[i].Split('|');
data.ID = columns[0].Trim();
data.IDNum = columns[1].Trim();
data.Date = columns[2].Trim();
data.Data = columns[3].Trim();
string someDate = columns[4].Trim();
if (someDate.Equals(""))
{
data.SomeDate = previousDate;
}
else
{
previousDate = someDate;
data.SomeDate = someDate;
}
data.TranCode = columns[5].Trim();
fileDatas.Add(data);
}
}
}
Please notice that I created a "FileData" class to use to store the values.
Also notice that I am going through this data backwards, as it's easier to assign the dates this way.
What this does:
This reads all the data from the file into a string. That string is then split by line ends (\r\n).
Once you have a list of lines, we go BACKWARDS through it (int i = lines.length - 1; i < 0; i--).
Going backwards, we simply assign data, except for the "somedate" column. Here we check to see if somedate has a value. If it does, we assign a "previousDate" variable that value, and then assign the value. If it doesn't have a value, we use the value from previousDate. This ensures it will change appropriately.
The one issue with this is actually a potential issue with the data. If the end of the file does not have a date, you will have blank values for the SomeDate column until the first time you encounter a date.
Compiled, tested, and working.
Related
I have a string of data that I would like to split up, for example my one string contains multiple characters, their stats and abilities they each have.
Full String:
"Andy,135,Punch-Kick-Bite-Headbutt|Tom,120,Bite-Slap-Dodge-Heal|Nathan,105,Bite-Scratch-Tackle-Kick"
So the above string has the characters seperated by "|" and the abilities that are seperated by "-".
I managed to divide them up by each character so its "Andy,135,Punch-Kick-Bite-Headbutt" in one index of array by doing this:
string myString = "Andy,135,Punch-Kick-Bite-Headbutt|Tom,120,Bite-Slap-Dodge-Heal|Nathan,105,Bite-Scratch-Tackle-Kick";
string[] character = myString.ToString().Split('|');
for (int i = 0; i < character.Length; i++)
{
Debug.Log("Character data: " + character[i].ToString());
}
Now How would I turn something like "Andy,135,Punch-Kick-Bite-Headbutt" and only retrieve the stats into a stat array so its "Andy,135" and pull Abilities into a string array so it is: "Punch-Kick-Bite-Headbutt"
So I would have my statArray as "Andy,135" and abilityArray as "Punch-Kick-Bite-Headbutt"
Well I would strongly recommend defining class to store that data:
public class Character
{
public string Name { get; set; }
public int Stat { get; set; }
public string[] Abilities { get; set; }
}
The I would write following LINQ:
// First split by pipe character to get each character (person)
// in raw format separately
var characters = longString.Split('|')
// Another step is to separate each property of a character,
// so it can be used in next Select method.
// Here we split by comma
.Select(rawCharacter => rawCharacter.Split(','))
// Finally we use splitted raw data and upon this, we create
// concrete object with little help of casting to int and
// assign abilities by splitting abilities list by hyphen -
.Select(rawCharacter => new Character()
{
Name = rawCharacter[0],
Stat = int.Parse(rawCharacter[1]),
Abilities = rawCharacter[2].Split('-'),
})
.ToArray();
I am working on a time clock program and I am having an issue getting my time punches to be in the correct order. The dates are in order, but the list.Sort() is putting the times out of order. It is sorting it like a string, which make sense because it is a string. 3:41PM is sorted before 7:20AM because 3 is before 7. See example:
12/17/2018 3:41:00 PM Clock Out Yes BB
12/17/2018 7:20:00 AM Clock In NO Not Needed
I am not sure how to accomplish this because of the information I am dumping into the list.
while (reader.Read())
{
timeClockDataList.Add(reader["Punch"].ToString() + "%" + reader["PunchType"].ToString() + "%" + reader["NeedsApproval"].ToString() + "%" + reader["Approval"].ToString());
}
I am putting the "%" in there so I can split the string at the % later to populate the time card with the punch time, type of punch, approval needed, and approval.
My question is how to sort this string by the Date AND Time?
EDIT
while (reader.Read())
{
timeClockDataList.Add(new ClockData
{
Punch = DateTime.Parse(reader["Punch"].ToString()),
PunchType = reader["PunchType"].ToString(),
NeedsApproval = reader["NeedsApproval"].ToString(),
Approval = reader["Approval"].ToString(),
});
//***This is the old code that makes one long string***
//timeClockDataList.Add(reader["Punch"].ToString() + "%" + ToString() + +
}
timeClockDataList.OrderBy(x => x.Punch);
//***This is the old code that would sort the list string***
//timeClockDataList.Sort();
using (StreamWriter writer = new StreamWriter(filePath, true))
{
for (int _i = 0; _i < timeClockDataList.Count; ++_i)
{
punch = timeClockDataList[_i].Punch.ToString();
punchType = timeClockDataList[_i].PunchType;
needsApproval = timeClockDataList[_i].NeedsApproval;
approval = timeClockDataList[_i].Approval;
writer.WriteLine(String.Format("{0,-5}{1,-30}{2,-20}{3,-11}{4,-15}", " ", punch, punchType, needsApproval, approval));
punch = null;
punchType = null;
needsApproval = null;
approval = null;
}
}
timeClockDataList is the wrong type. When everything is one big string then you don't have data, you just have one big string.
Make a custom object to store your data. For example:
class ClockData
{
public DateTime Punch { get; set; }
public string PunchType { get; set; }
// etc.
}
Read your data into a list of that class:
while (reader.Read())
{
timeClockDataList.Add(new ClockData
{
Punch = DateTime.Parse(reader["Punch"].ToString()),
PunchType = reader["PunchType"].ToString(),
// etc.
});
}
Now you have actual data, which can be manipulated/sorted/etc. easily:
timeClockDataList.OrderBy(x => x.Punch)
You may also want to throw in some error checking when populating it, use TryParseExact for the DateTime, etc. There are a variety of improvements you can make. Eventually, when you want to display the data, that's when you output it as a string. (You can make that very simple by overriding .ToString() on the custom class.)
The field Day[] calendar = new Day[365]; contains the class Day. As the teacher wanted.
But I don't know how to make my method AddRecord to save in this field. I use
hw.Add(new Homework(Convert.ToDateTime(part), parts[1], parts[2]));
to add it to List. But I need to save the data to the Day[] calendar = new Day[365]; I just don't know how.
Class Calendar
class Calendar
{
Day d = new Day();
List<Homework> hw;
Day[] calendar = new Day[365];
//Day[0] = (Convert.ToDateTime("9.3.2008 16:05"), "M", "text"));
public Calendar()
{
hw = d.GetList();
}
public void AddRecord(string line)
{
string[] parts = line.Split(' ');
string part = parts[0] + " " + parts[1];
hw.Add(new Homework(Convert.ToDateTime(part), parts[1], parts[2]));
}
class Day
class Day
{
List<Homework> hw = new List<Homework>();
public List<Homework> GetList()
{
hw = new List<Homework>();
string datum = "29.5.2005 16:55"; //!
hw.Add(new Homework(Convert.ToDateTime(datum), "INF", "THREE"));// !
return hw;
}
}
class Homework
class Homework
{
public DateTime dt; }
public string subject;
public string content;
public Homework(DateTime dt, string subject, string content)
{
String.Format("{0:d.m.yyyy HH:mm}", dt);
this.dt = dt;
this.subject = subject;
this.content = content;
}
}
If I understand what you are trying to accomplish; you want to add the Homeworkrecord to its corresponding Day that is held by the Calendar object.
So first, we need to get the day:
DateTime dataDate = Convert.ToDateTime(part); //Or something
Day dueDate = calendar.FirstOrDefault(d => d.Date = dataDate);
Note that this probably won't work first time, as you need to compare just the day. If you created the Day object with a different time than the Homework item had, the forthcoming null check will fail. I'll leave that comparison as an exercise to you, but feel free to leave a comment if you can't figure it out.
Then we need to give it the homework item:
if (dueDate != null) //Check if we found the date!
dueDate.AddHomeworkItem(new Homework(dataDate, parts[2], parts[3]));
else
throw new Exception("Date not found; invalid data read"); //Or something
//Failing silently is usually bad
Of course, that requires a method in the Day class:
public void AddHomeworkItem(Homework item)
{
hw.Add(item);
}
Thats it! A couple things I noticed while looking at your code:
You have a Day and List<Homework> in your Calendar class. You shouldn't need either of them. The Day[] is sufficient from what I can see.
It looked like you reused parts[1] in your add function. I doubt you want the date to be part of the subect! I fixed it in my code.
Your Day class pre-populates its Homework list with a nonsensical item. You probably need to remove that.
I have the following code:
class Program
{
static void Main(string[] args)
{
string linie;
foreach (string elem in Directory.GetFiles(#"C:\Users\A\Desktop\FIles", "*.txt"))
{
Console.WriteLine(elem);
StreamReader reader = new StreamReader(elem);
{
while (!reader.EndOfStream)
{
linie=reader.ReadLine();
Console.WriteLine(linie);
}
}
reader.Close();
}
Console.ReadKey();
Console.WriteLine(DateTime.ParseExact("5/10/2005", "m/d/yyyy", null).Day);
}
}
What i need is to select only the Date from a file.
For example if i have the string "the date is 20/2/2012" in a .txt file, i need to substract only 20/2/2012 and to compare it with the current date.
If you want an easy lazy solution, you can always add a : and Split on it. (You could split on white spaces but then I would have to count for the index and I don't want to do this).
string dateFromFile = "The date is : 20/2/2012";
string[] dateString = dateFromFile.Split(':');
string myDate = dateString[1];
Ok I looked at my answer and decided I was too lazy...
string dateFromFile = "The date is 20/2/2012";
string[] dateString = dateFromFile.Split(' ');
string myDate = dateString[3];
It splits the string everytime it sees the sepcified character and returns a String[].
In the second example (where I split on white space, the array would look like this)
dateString[0] = "The"
dateString[1] = "date"
dateString[2] = "is"
dateString[3] = "20/2/2012"
Basically,
I have text I want to spit out from a block of text. I have the regular expression down for the most part however, It's either too little[skips a section] or too much[reads part of the next section].It basically needs to read text that I extracted from a bank statement.I already tried reading up on regular expressions more, however I still have no clue as to what to do.
Heres a bit of a sample for you guys to understand what I'm trying to do.
_4XXXXXXXXXXXXXX9_
_SOU THE HOME DEPOT 431 POMPANO BEACH * FL
AUT 020112 DDA PURCHASE_
_2/1_DEBIT POS_3.15_
The underscores are basically parts I want to extract. Basically everything except the DEBIT POS basically.
And the regex I'm using is:
\A
(?<SerialNumber>\b[0-9]{13,16}\b)
(?<Description>.) 'PROBLEM HERE'
(?<PostingDate>
(?:1[0-2]|[1-9])/(?:3[01]|[12][0-9]|[1-9]))
(?<Amount>[,0-9]+\.[0-9]{2})
\Z
I cant set the Description to be from any length of characters because I don't know the maximum length that the text portion will be. I also don't know if it's 2 lines for description or just 1. Thats mainly whats confusing me.
I imagine you want to join every four lines together as one line first:
var file = #"C:\temp.txt";
var lines = System.IO.File.ReadAllLines(file);
var buffer = new List<String>();
for (var i = 0; i < lines.Length; i++ )
{
if (i % 4 == 0) { buffer.Add(""); }
buffer[buffer.Count - 1] += lines[i] + " ";
}
buffer.ForEach(b => Console.WriteLine(b));
Then you can actually parse each entry in buffer as if it's one line. This can be done easily using either regex or just string Substrings. Far easier than trying to do it across lines.
The above code isn't the cleanest, but it works.
Look like another simple answer of don't use Regex. If each of these are lines, it wouldn't be that hard to File.ReadAllLines() and parse each line.
public class Order
{
public string SerialNumber { get; set; }
public string Description { get; set; }
public DateTime PostingDate { get; set; }
public Decimal Amount { get; set; }
public void SetSerialNumberFromRaw(string serialNumber)
{
// Convert to required type, etc.
this.SerialNumber = <someConvertedValue>;
}
public void <OtherNeededValueConverters>
}
List<string> lines = File.ReadAlllines("<filename").ToList();
List<Order> orders = new List<Order>();
Order currentOrder = null;
foreach (string line in lines)
{
if (currentOrder = null)
{
currentOrder = new Order();
orders.Add(currentOrder);
currentOrder.SetSerialNumberFromRaw(line);
}
else
{
if (line.Contains("DEBIT POS", CultureInfo.CurrentCultureIngoreCase))
{
currentOrder.SetPostingDateAndAmount(line);
currentOrder = null;
}
else
{
currentOrder.SetAppendDescription(line);
}
}
}