【问题标题】:Get the positions of unique elements in a string[]获取字符串中唯一元素的位置[]
【发布时间】:2015-03-16 11:34:29
【问题描述】:

我有一个 xml 文件,我正在访问该文件以创建项目所用时间的报告。我将唯一日期返回到在 winform 上动态创建的标签,并希望编译每个唯一日期在项目上花费的时间。我已经能够退回每个日期下的所有项目或仅一个项目。目前我坚持只返回一个项目。谁能帮帮我吗??如果数据正确,这就是数据的样子。

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.

这就是我检索数据的方式

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

这就是我获取唯一日期的方式。

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

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

这就是我创建标签的方式。

        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;
                             }
                        }

                     }
              }
         }

我已经坚持了大约 3 个月。有没有人可以向我描述为什么我无法正确检索与特定日期相关的工作编号。我不相信这些是专门作为日期返回的。只是一个看起来像日期的字符串。

我非常感谢我能得到的任何帮助。我完全感到困惑。感谢您提前回复。我非常感谢您的帮助。

编辑:@Sayka - 这是 xml 示例。

<?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>

这就是我从 xml 文件中获取信息并返回字符串 [] 的方式。

    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 和 Ticks 以类似的方式返回。我已经能够在整个代码中重用这些 sn-ps。这是一个一维的xml文件??它将始终返回与日期或刻度相等的工作编号的位置。我永远不会有更多或更少的任何一种元素。

【问题讨论】:

  • 你使用调试器了吗?断点?单步执行您的代码?将预期值与实际值进行比较?第一个不匹配在哪里?首先出错的是什么?它究竟发生在哪里?为什么?
  • 在 posJobNumber = ... 的 'foreach()' 中。它返回与第一个日期匹配的第一个作业编号,然后继续循环。就好像它在那个语句中没有增加。我不明白(我认为)这个 LINQ 语句??我想这就是所谓的。我最初试图返回 .IndexOf 但我无法只返回那些成功匹配日期的。
  • 你怎么会用不懂的LINQ语句?将其编码为显式循环,看看是否效果更好。
  • 嗯,这听起来像是我必须做的。我会回到IndexOf。我认为它想吸收所有元素,而不仅仅是匹配的元素。感谢您的建议@DrKoch。我很感激:-D
  • 怎么能把Label的名字,一个数字?

标签: c# winforms dynamic labels


【解决方案1】:

您可以使用 Linq-to-XML 解析 XML 文件,然后使用 Linq-to-objects 按作业日期对数据进行分组(和排序),并按作业名称对每个组进行排序。

解析XML文件的代码如下:

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"))
});

按日期对作业进行分组和排序并按作业名称对组进行排序的代码是:

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

然后您可以通过遍历result 中的每个组来访问数据,然后遍历组中的每个作业,如下所示:

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);
}

将所有这些放在一个示例可编译控制台应用程序中(根据需要替换 XML 文件的文件名):

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);
            }
        }
    }
}

【讨论】:

  • 但是他想从一个xml文件中获取数据
  • @Sayka 他在我回答时更新了他的问题......我必须修改。
  • @MatthewWatson 这需要一些时间来消化。感谢您提供如此完整的答案。它看起来像一个完全不同的方向,但如果它有效,那就太棒了:-D 我肯定会检查它并更新你。非常感谢。
  • @Frank 最好的方法可能是在调试器中单步执行它,并尝试使用 XML 文件中的不同数据集来检查输出是否是您想要的。
  • @MatthewWatson 是的。 Step Debugging 很糟糕,但它可以工作 :-) 即使是小文件也可能很乏味。
【解决方案2】:

输出是这样的

创建一个新项目

将表单尺寸设置得更大。

应用这些代码。

为您的 XML 文件设置位置。

命名空间

using System.Xml;
using System.IO;

表单代码

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; }
    }
}

【讨论】:

  • 谢谢赛卡。哇,很多。我不以编码为生,但我肯定会检查一下。我回去做了更多的研究,看来我错了。 DataGridViews 对图表很有帮助,所以我对此非常感兴趣。谢谢:-D
猜你喜欢
  • 2017-04-09
  • 1970-01-01
  • 2018-05-27
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-05-10
  • 1970-01-01
相关资源
最近更新 更多