查找数组或XML中的值的频率(C#)

时间:2008-12-17 20:40:20

标签: c# xml linq linq-to-xml frequency

我有一个XML提要(我无法控制),我试图弄清楚如何检测文档中某些属性值的数量。

我也在解析XML并将属性分离为Arrays(用于其他功能)

以下是我的XML

示例
<items>
<item att1="ABC123" att2="uID" />
<item att1="ABC345" att2="uID" />
<item att1="ABC123" att2="uID" />
<item att1="ABC678" att2="uID" />
<item att1="ABC123" att2="uID" />
<item att1="XYZ123" att2="uID" />
<item att1="XYZ345" att2="uID" />
<item att1="XYZ678" att2="uID" />
</items>

我想根据每个att1值找到卷节点。 Att1值会改变。一旦我知道att1值的频率,我需要拉出该节点的att2值。

我需要找到TOP 4项并提取其属性的值。

所有这些都需要在C#代码后面完成。

如果我使用的是Javascript,我会创建一个关联数组,并将att1作为键,频率为值。但由于我是c#的新手,我不知道如何在c#中复制它。

所以我相信,首先我需要在XML中找到所有唯一的att1值。我可以这样做:

IEnumerable<string> uItems = uItemsArray.Distinct();
// Where uItemsArray is a collection of all the att1 values in an array

然后我不知道如何将每个唯一的att1值与整个文档进行比较,以获得存储在变量或数组或任何数据集中的音量。

以下是我最终使用的代码段:

        XDocument doc = XDocument.Load(@"temp/salesData.xml");
        var topItems = from item in doc.Descendants("item")
                    select new
                    {
                        name = (string)item.Attribute("name"),
                        sku = (string)item.Attribute("sku"),
                        iCat = (string)item.Attribute("iCat"),
                        sTime = (string)item.Attribute("sTime"),
                        price = (string)item.Attribute("price"),
                        desc = (string)item.Attribute("desc")

                    } into node
                    group node by node.sku into grp
                    select new { 
                        sku = grp.Key,
                        name = grp.ElementAt(0).name,
                        iCat = grp.ElementAt(0).iCat,
                        sTime = grp.ElementAt(0).sTime,
                        price = grp.ElementAt(0).price,
                        desc = grp.ElementAt(0).desc,
                        Count = grp.Count() 
                    };

        _topSellers = new SalesDataObject[4];
        int topSellerIndex = 0;
        foreach (var item in topItems.OrderByDescending(x => x.Count).Take(4))
        {
            SalesDataObject topSeller = new SalesDataObject();
            topSeller.iCat = item.iCat;
            topSeller.iName = item.name;
            topSeller.iSku = item.sku;
            topSeller.sTime = Convert.ToDateTime(item.sTime);
            topSeller.iDesc = item.desc;
            topSeller.iPrice = item.price;
            _topSellers.SetValue(topSeller, topSellerIndex);
            topSellerIndex++;
        } 

感谢您的帮助!

3 个答案:

答案 0 :(得分:4)

您使用的是.NET 3.5吗? (看起来它基于你的代码。)如果是这样,我怀疑使用LINQ to XML和LINQ to Objects这很容易。但是,我担心你的例子不清楚你想要什么。具有相同att1 的所有值是否具有相同的att2?如果是这样,它就像:

var results = (from element in items.Elements("item")
              group element by element.Attribute("att1").Value into grouped
              order by grouped.Count() descending
              select grouped.First().Attribute("att2").Value).Take(4);

我还没有测试过,但是我认为它应该有用......

  • 我们从所有项目元素开始
  • 我们按照att1值
  • 对它们进行分组(仍作为元素)
  • 我们按照大小对这些组进行排序,然后降序,这是最大的一个
  • 从每个组中我们取第一个元素来查找其att2值
  • 我们采取了这些结果中的前四位

答案 1 :(得分:1)

如果你有这些值,你应该能够使用LINQ的GroupBy ......

        XDocument doc = XDocument.Parse(xml);
        var query = from item in doc.Descendants("item")
                    select new
                    {
                        att1 = (string)item.Attribute("att1"),
                        att2 = (string)item.Attribute("att2") // if needed
                    } into node
                    group node by node.att1 into grp
                    select new { att1 = grp.Key, Count = grp.Count() };

        foreach (var item in query.OrderByDescending(x=>x.Count).Take(4))
        {
            Console.WriteLine("{0} = {1}", item.att1, item.Count);
        }

答案 2 :(得分:1)

您可以使用LINQ / XLINQ来完成此任务。下面是我刚刚编写的示例控制台应用程序,因此代码可能没有进行优化,但它可以正常工作。

using System;
using System.Collections.Generic;
using System.Linq;
using System.Xml.Linq;
using System.Text;

namespace FrequencyThingy
{
    class Program
    {
        static void Main(string[] args)
        {
            string data = @"<items>
                            <item att1=""ABC123"" att2=""uID"" />
                            <item att1=""ABC345"" att2=""uID"" />
                            <item att1=""ABC123"" att2=""uID"" />
                            <item att1=""ABC678"" att2=""uID"" />
                            <item att1=""ABC123"" att2=""uID"" />
                            <item att1=""XYZ123"" att2=""uID"" />
                            <item att1=""XYZ345"" att2=""uID"" />
                            <item att1=""XYZ678"" att2=""uID"" />
                            </items>";
            XDocument doc = XDocument.Parse(data);
            var grouping = doc.Root.Elements().GroupBy(item => item.Attribute("att1").Value);

            foreach (var group in grouping)
            {
                var groupArray = group.ToArray();
                Console.WriteLine("Group {0} has {1} element(s).", groupArray[0].Attribute("att1").Value, groupArray.Length);
            }

            Console.ReadKey();
        }
    }
}