Get the positions of unique elements in a string[]

旧巷老猫 提交于 2019-12-12 03:59:13

问题


I have an xml file that I am accessing to create a report of time spent on a project. I'm returning the unique dates to a label created dynamically on a winform and would like to compile the time spent on a project for each unique date. I have been able to return all of the projects under each date or only one project. Currently I'm stuck on only returning one project. Can anyone please help me?? This is what the data should look like if it's correct.

04/11/15
    26820   2.25
    27111   8.00
04/12/15
    26820   8.00
04/13/15
    01det   4.33
    26820   1.33
    27225   4.25

etc.

This is how I'm retrieving the data

         string[] weekDateString = elementDateWeekstring();
         string[] uniqueDates = null;
         string[] weeklyJobNumber = elementJobNumWeek();
         string[] weeklyTicks = elementTicksWeek();

This is how I'm getting the unique dates.

         IEnumerable<string> distinctWeekDateIE = weekDateString.Distinct();

         foreach (string d in distinctWeekDateIE)
         {
             uniqueDates = distinctWeekDateIE.ToArray();
         }

And this is how I'm creating the labels.

        try
         {
              int dateCount;
              dateCount = uniqueDates.Length;

              Label[] lblDate = new Label[dateCount];
              int htDate = 1;
              int padDate = 10;

              for (int i = 0; i < dateCount; i++ )
              {
                   lblDate[i] = new Label();

                   lblDate[i].Name = uniqueDates[i].Trim('\r');

                   lblDate[i].Text = uniqueDates[i];

                   lblDate[i].TabIndex = i;

                   lblDate[i].Bounds = new Rectangle(18, 275 + padDate + htDate, 75, 22);

                   targetForm.Controls.Add(lblDate[i]);

                   htDate += 22;

                   foreach (string x in uniqueDates)
                   {
                        int[] posJobNumber;

                       posJobNumber = weekDateString.Select((b, a) => b == uniqueDates[i].ToString() ? a : -1).Where(a => a != -1).ToArray();

                        for (int pjn = 0; pjn < posJobNumber.Length; pjn++)
                        {

                             if (x.Equals(lblDate[i].Text))
                             {

                                  Label lblJobNum = new Label();

                                  int htJobNum = 1;
                                  int padJobNum = 10;

                                  lblJobNum.Name = weeklyJobNumber[i];

                                  lblJobNum.Text = weeklyJobNumber[i];

                                  lblJobNum.Bounds = new Rectangle(100, 295 + padJobNum + htJobNum, 75, 22);

                                  targetForm.Controls.Add(lblJobNum);

                                  htJobNum += 22;
                                  htDate += 22;
                                  padJobNum += 22;
                             }
                        }

                     }
              }
         }

I've been stuck on this for about 3 months. Is there anyone that can describe to me why I'm not able to properly retrieve the job numbers that are associated with a particular date. I don't believe that these are specifically being returned as dates. Just a string that looks like a date.

I really appreciate any help I can get. I'm just completely baffled. Thank you for any responses in advance. I truly appreciate the assistance.

EDIT: @Sayka - Here is the xml sample.

<?xml version="1.0" encoding="utf-8"?>
<Form1>
  <Name Key="4/21/2014 6:51:17 AM">
    <Date>4/21/2014</Date>
    <JobNum>26820</JobNum>
    <RevNum>00000</RevNum>
    <Task>Modeling Secondary</Task>
    <Start>06:51 AM</Start>
    <End>04:27 PM</End>
    <TotalTime>345945089017</TotalTime>
  </Name>
  <Name Key="4/22/2014 5:44:22 AM">
    <Date>4/22/2014</Date>
    <JobNum>26820</JobNum>
    <RevNum>00000</RevNum>
    <Task>Modeling Secondary</Task>
    <Start>05:44 AM</Start>
    <End>06:56 AM</End>
    <TotalTime>43514201221</TotalTime>
  </Name>
  <Name Key="4/22/2014 6:57:02 AM">
    <Date>4/22/2014</Date>
    <JobNum>02e-n-g</JobNum>
    <RevNum>00000</RevNum>
    <Task>NET Eng</Task>
    <Start>06:57 AM</Start>
    <End>07:16 AM</End>
    <TotalTime>11706118875</TotalTime>
  </Name>
....
</Form1>

This is how I'm getting the information out of the xml file and returning a string[].

    public static string[] elementDateWeekstring()
    {
        //string datetxtWeek = "";
        XmlDocument xmldoc = new XmlDocument();

        fileExistsWeek(xmldoc);

        XmlNodeList nodeDate = xmldoc.GetElementsByTagName("Date");

        int countTicks = 0;
        string[] dateTxtWeek = new string[nodeDate.Count];


        for (int i = 0; i < nodeDate.Count; i++)
        {
            dateTxtWeek[i] = nodeDate[i].InnerText;
            countTicks++;

        }
        return dateTxtWeek;
    }

Job number and Ticks are returned in a similar fashion. I've been able to reuse these snippets throught out the code. This is a one dimensional xml file?? It will always return a position for a jobnumber that equates to a date or Ticks. I will never have more or less of any one element.


回答1:


You can use Linq-to-XML to parse the XML file, and then use Linq-to-objects to group (and order) the data by job date and order each group by job name.

The code to parse the XML file is like so:

var doc = XDocument.Load(filename);
var jobs = doc.Descendants("Name");

// Extract the date, job number, and total time from each "Name" element.:

var data = jobs.Select(job => new
{
    Date = (DateTime)job.Element("Date"),
    Number = (string)job.Element("JobNum"),
    Duration = TimeSpan.FromTicks((long)job.Element("TotalTime"))
});

The code to group and order the jobs by date and order the groups by job name is:

var result = 
    data.GroupBy(job => job.Date).OrderBy(g => g.Key)
    .Select(g => new
    {
        Date = g.Key, 
        Jobs = g.OrderBy(item => item.Number)
    });

Then you can access the data by iterating over each group in result and then iterate over each job in the group, like so:

foreach (var jobsOnDate in result)
{
    Console.WriteLine("{0:d}", jobsOnDate.Date);

    foreach (var job in jobsOnDate.Jobs)
        Console.WriteLine("    {0}  {1:hh\\:mm}", job.Number, job.Duration);
}

Putting this all together in a sample compilable console application (substitute the filename for the XML file as appropriate):

using System;
using System.Linq;
using System.Xml.Linq;

namespace ConsoleApplication2
{
    class Program
    {
        private static void Main()
        {
            string filename = @"d:\test\test.xml"; // Substitute your own filename here.

            // Open XML file and get a collection of each "Name" element.            

            var doc = XDocument.Load(filename);
            var jobs = doc.Descendants("Name");

            // Extract the date, job number, and total time from each "Name" element.:

            var data = jobs.Select(job => new
            {
                Date = (DateTime)job.Element("Date"),
                Number = (string)job.Element("JobNum"),
                Duration = TimeSpan.FromTicks((long)job.Element("TotalTime"))
            });

            // Group the jobs by date, and order the groups by job name:

            var result = 
                data.GroupBy(job => job.Date).OrderBy(g => g.Key)
                .Select(g => new
                {
                    Date = g.Key, 
                    Jobs = g.OrderBy(item => item.Number)
                });

            // Print out the results:

            foreach (var jobsOnDate in result)
            {
                Console.WriteLine("{0:d}", jobsOnDate.Date);

                foreach (var job in jobsOnDate.Jobs)
                    Console.WriteLine("    {0}  {1:hh\\:mm}", job.Number, job.Duration);
            }
        }
    }
}



回答2:


The output is like this

Create a new project

Set form size bigger.

Apply these codes.

Set the location for your XML file.

Namespaces

using System.Xml;
using System.IO;

Form Code

public partial class Form1 : Form
{
    const string XML_FILE_NAME = "D:\\emps.txt";
    public Form1()
    {
        InitializeComponent();
    }

    private void Form1_Load(object sender, EventArgs e)
    {
        prepareDataGrid();
        List<JOBS> jobsList = prepareXML(XML_FILE_NAME);
        for (int i = 0; i < jobsList.Count; i++)
        {
            addDateRow(jobsList[i].jobDate.ToString("M'/'d'/'yyyy"));
            for (int j = 0; j < jobsList[i].jobDetailsList.Count; j++)
                dgv.Rows.Add(new string[] { 
                    jobsList[i].jobDetailsList[j].JobNumber,
                    jobsList[i].jobDetailsList[j].JobHours
                });
        }
    }

    DataGridView dgv;
    void prepareDataGrid()
    {
        dgv = new DataGridView();
        dgv.BackgroundColor = Color.White;
        dgv.GridColor = Color.White;
        dgv.DefaultCellStyle.SelectionBackColor = Color.White;
        dgv.DefaultCellStyle.SelectionForeColor = Color.Black;
        dgv.DefaultCellStyle.ForeColor = Color.Black;
        dgv.DefaultCellStyle.BackColor = Color.White;
        dgv.DefaultCellStyle.Alignment = DataGridViewContentAlignment.MiddleRight;
        dgv.Width = 600;
        dgv.Dock = DockStyle.Left;
        this.BackColor = Color.White;
        dgv.Columns.Add("Col1", "Col1");
        dgv.Columns.Add("Col2", "Col2");
        dgv.Columns[0].Width = 110;
        dgv.Columns[1].Width = 40;
        dgv.DefaultCellStyle.Font = new System.Drawing.Font("Segoe UI", 10);
        dgv.RowHeadersVisible = dgv.ColumnHeadersVisible = false;
        dgv.AllowUserToAddRows =
        dgv.AllowUserToDeleteRows =
        dgv.AllowUserToOrderColumns =
        dgv.AllowUserToResizeColumns =
        dgv.AllowUserToResizeRows =
        !(dgv.ReadOnly = true);
        Controls.Add(dgv);
    }

    void addJobRow(string jobNum, string jobHours)
    {
        dgv.Rows.Add(new string[] {jobNum, jobHours });
    }

    void addDateRow(string date)
    {
        dgv.Rows.Add(new string[] { date, ""});
        dgv.Rows[dgv.Rows.Count - 1].DefaultCellStyle.SelectionForeColor =
        dgv.Rows[dgv.Rows.Count - 1].DefaultCellStyle.ForeColor = Color.Firebrick;
        dgv.Rows[dgv.Rows.Count - 1].DefaultCellStyle.Font = new Font("Segoe UI Light", 13.5F);
        dgv.Rows[dgv.Rows.Count - 1].DefaultCellStyle.Alignment = DataGridViewContentAlignment.MiddleLeft;
        dgv.Rows[dgv.Rows.Count - 1].Height = 25;
    }

    List<JOBS> prepareXML(string fileName)
    {
        string xmlContent = "";
        using (FileStream fs = new FileStream(fileName, FileMode.Open, FileAccess.Read))
        using (StreamReader sr = new StreamReader(fs)) xmlContent = sr.ReadToEnd();
        XmlDocument doc = new XmlDocument();
        doc.LoadXml(xmlContent);

        List<JOBS> jobsList = new List<JOBS>();
        XmlNode form1Node = doc.ChildNodes[1];
        for (int i = 0; i < form1Node.ChildNodes.Count; i++)
        {
            XmlNode dateNode = form1Node.ChildNodes[i].ChildNodes[0].ChildNodes[0],
                jobNumNode = form1Node.ChildNodes[i].ChildNodes[1].ChildNodes[0],
                timeTicksNode = form1Node.ChildNodes[i].ChildNodes[6].ChildNodes[0];

            bool foundDate = false;
            for (int j = 0; j < jobsList.Count; j++) if (jobsList[j].compareDate(dateNode.Value))
                {
                    jobsList[j].addJob(jobNumNode.Value, Math.Round(TimeSpan.FromTicks(
                        (long)Convert.ToDouble(timeTicksNode.Value)).TotalHours, 2).ToString());
                    foundDate = true;
                    break;
                }
            if (!foundDate)
            {
                JOBS job = new JOBS(dateNode.Value);
                string jbnum = jobNumNode.Value;
                string tbtck = timeTicksNode.Value;
                long tktk = Convert.ToInt64(tbtck);
                double tkdb = TimeSpan.FromTicks(tktk).TotalHours;
                job.addJob(jobNumNode.Value, Math.Round(TimeSpan.FromTicks(
                        Convert.ToInt64(timeTicksNode.Value)).TotalHours, 2).ToString());
                jobsList.Add(job);
            }
        }
        jobsList.OrderByDescending(x => x.jobDate);
        return jobsList;
    }

    class JOBS
    {
        public DateTime jobDate;
        public List<JobDetails> jobDetailsList = new List<JobDetails>();

        public void addJob(string jobNumber, string jobHours)
        {
            jobDetailsList.Add(new JobDetails() { JobHours = jobHours, JobNumber = jobNumber });
        }
        public JOBS(string dateString)
        {
            jobDate = getDateFromString(dateString);
        }

        public JOBS() { }

        public bool compareDate(string dateString)
        {
            return getDateFromString(dateString) == jobDate;
        }

        private DateTime getDateFromString(string dateString)
        {
            string[] vals = dateString.Split('/');
            return new DateTime(Convert.ToInt32(vals[2]), Convert.ToInt32(vals[0]), Convert.ToInt32(vals[1]));
        }
    }

    class JobDetails
    {
        public string JobNumber { get; set; }
        public string JobHours { get; set; }
    }
}


来源:https://stackoverflow.com/questions/29075817/get-the-positions-of-unique-elements-in-a-string

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!