【问题标题】:C# ListView - Searching for exact time value (HH:mm:ss) or closest valueC# ListView - 搜索准确的时间值 (HH:mm:ss) 或最接近的值
【发布时间】:2017-01-01 21:18:24
【问题描述】:

我正在寻找一种在列表视图中搜索精确值或列表中最接近它的值的方法。

这些值都是时间值(“HH:mm:ss”)。我还没有写很多代码,但我会发布我目前所写的。

以下方法引用了一个名为 lstData 的 ListView,它保存了时间值。索引被传递给选择特定时间的方法。 我想要做的是在 lstData 中的这个位置取值,并在另一个名为 lstReport 的 ListView 中找到相同的值或最接近的值。 lst Report 不一定有相同的时间值,但有很多类似的,格式相同,因此我希望选择 lstReport 中最接近的值。

private void SelectTime(int val)
    {
        try
        {
            CurrentIndex = val;
            lstData.Items[CurrentIndex].Selected = true;
            lstData.EnsureVisible(CurrentIndex);

            String text = lstData.Items[CurrentIndex].Text;
            MessageBox.Show("Time Selected: " + text);


            // This is where I want to search lstReport for the closest time value 
            // to lstData.Items[CurrentIndex] value

            this.Refresh();
        }
        catch
        {
        }
    }

如果我没有很好地解释这一点,我深表歉意,如果是这种情况,请发表评论,我会尽量让它更清楚。谢谢

编辑

// get the selected item from lstData
            String text = lstData.Items[CurrentIndex].Text;

            // parse the value
            long SelectedDate = DateTime.Parse(text).Ticks;
            //  extract the listview items into a list of strings
            List<string> list = lstData.Items.Cast<ListViewItem>().Select(item => item.Text).ToList();
            //By converting the values to Long, we can get the closest value using Math.Abs.
            string closest = list.Aggregate((x, y) => Math.Abs(DateTime.Parse(x).Ticks - SelectedDate) < Math.Abs(DateTime.Parse(y).Ticks - SelectedDate) ? x : y);

【问题讨论】:

  • 对于第二个列表的每个项目,减去日期项目,得到 timeSpan 的 totalSeconds,执行 Math.Abs​​() 并保持最低结果可能会成功

标签: c# list listview arraylist listviewitem


【解决方案1】:

您可以使用 LINQ 通过对时间的绝对差进行排序来获得最接近的值。假设您有DateTime 类型的两个列表lstReportlstData。然后像这样做

private void SelectTime(int val)
{
    try
    {
        CurrentIndex = val;
        lstData.Items[CurrentIndex].Selected = true;
        lstData.EnsureVisible(CurrentIndex);

        String text = lstData.Items[CurrentIndex].Text;
        MessageBox.Show("Time Selected: " + text);

        //Get the closest DateTime to the Current item of lstData
        DateTime MinimumDifferenceItem = lstReport.Items.Cast<DateTime>().OrderBy(Dt => Math.Abs((Dt - (DateTime)lstData.Items[CurrentIndex]).Milliseconds)).First();

        this.Refresh();
    }
    catch { }
}

别忘了添加

using System.Linq;

到您的文件。

编辑:

如果您的列表只包含字符串,您可以通过添加Convert.ToDateTime 来修改查询

String MinimumDifferenceItem = lstReport.Items.Cast<string>().OrderBy(Ts => Math.Abs((Convert.ToDateTime(Ts) - Convert.ToDateTime(lstData.Items[CurrentIndex])).Milliseconds)).First();

【讨论】:

  • 您好,感谢您的回复。我收到错误消息:ListView 不包含“OrderBy”的定义
  • 对不起,小错误:使用 lstReport.Items.OrderBy(...);
  • 没问题,由于某种原因它仍然不喜欢 OrderBy 并抛出相同的错误
  • 我已经向查询器添加了 Cast()。现在它应该可以正常工作了!
  • 非常感谢,我还需要转换 lstData.Items[CurrentIndex] 吗?它说 Operator '-' cannot be applied to type DateTime 和 ListViewItem
【解决方案2】:

您应该在列表视图中使用TimeSpan 而不是string。否则您将不得不进行不必要的转换。

从第一个列表视图中获取时间后,循环遍历第二个列表视图并计算两者之间的差异,跟踪第二个列表中的索引和单独变量中的差异。当您在第二个列表中找到更接近的时间时,更新索引和差异变量。

完成后,您应该获得第二个列表中最接近第一个列表中的时间的时间。列表视图应该在 TimeSpan 上自动调用 ToString(),所以它应该可以正常显示。

【讨论】:

    【解决方案3】:
       //Example List containing the time values
            List<string> dates = new List<string>();
            dates.Add("00:00:01");
            dates.Add("00:00:02");
            dates.Add("00:00:03");
            dates.Add("00:00:09");
            dates.Add("00:00:05");
            dates.Add("00:00:07");
    
            //The time value selected in the listview
            long SelectedDate = DateTime.Parse("00:00:04").Ticks;
    
            //By converting the values to Long, we can get the closest value using Math.Abs.
            string closest = dates.Aggregate((x, y) => Math.Abs(DateTime.Parse(x).Ticks - SelectedDate) < Math.Abs(DateTime.Parse(y).Ticks - SelectedDate) ? x : y);
    

    更新符合您的要求:

    您提到您有两个列表视图 lstData 和 lstReport。您从 lstData 中选择一个值,并希望输出 lstReport 中包含的最接近的值。 只需尝试以下步骤:

    1. 将所选值存储在字符串变量中
      String text = lstData.Items[CurrentIndex].Text;
    2. 将其转换为 Long 类型:
      long selectedvalue = DateTime.Parse(text).Ticks;
    3. 将 lsReport 中的项目转换为字符串列表:
      List&lt;string&gt; valuelist = lstReport.Items.Cast&lt;ListViewItem&gt;().Select(item =&gt; item.Text) .ToList();
    4. 将值列表与选定值进行比较以获得最接近的值:
      string closest = valuelist.Aggregate((x, y) =&gt; Math.Abs(DateTime.Parse(x).Ticks - selectedvalue) &lt; Math.Abs(DateTime.Parse(y).Ticks - selectedvalue) ? x : y);

    【讨论】:

    • 您好,感谢您的回复。我收到错误消息:ListView 不包含“聚合”的定义
    • 您所要做的就是将 listviewitems 提取到字符串列表中:List&lt;string&gt; list = lstData.Items.Cast&lt;ListViewItem&gt;() .Select(item =&gt; item.Text) .ToList();
    • 您好,我试过了,它总是显示最接近的时间与所选时间完全相同。
    • 没错没错,但是最接近的匹配和值都是一样的,并且closes的值是lstReport中没有的值。
    • 你能检查一下我在原帖底部的编辑吗,我可能还是编码错误,谢谢Innat3。
    猜你喜欢
    • 2011-10-09
    • 1970-01-01
    • 2017-08-01
    • 1970-01-01
    • 1970-01-01
    • 2020-12-19
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多