Любые советы по оптимизации для этой крошечной функции C #? - PullRequest
0 голосов
/ 19 марта 2012

Я получил XML-файл размером 9 МБ.По-видимому, он не работает.

Я хочу проверить, есть ли на каком-либо элементе уровня 2 родственный элемент с таким же значением атрибута "Id".

В настоящее время это идет слишком медленно.Какую оптимизацию я могу внести в этот код?

Отредактировано, чтобы включить некоторые советы

namespace ConsoleApplication1{
  using System;
  using System.Collections.Generic;
  using System.Diagnostics;
  using System.IO;
  using System.Linq;
  using System.Xml.Linq;
  internal class Program{
    private const string _pathToXml=@"C:\4\4";
    private static readonly List<object> _duplicateLeafs=new List<object>();
    private static void Main(){
      var xml=ReadXml();
      var elements=xml.Descendants();
      foreach(var element in elements)
        FindDupes(element);
      Console.ReadLine();
      Debugger.Break();
    }
    private static XDocument ReadXml(){
      return XDocument.Parse(File.ReadAllText(_pathToXml));
    }
    private static void FindDupes(XElement element){
      var elements=element.Descendants();
      var elementsWithIds=elements.Where(x=>x.Attribute("Id")!=null);
      var ids=elementsWithIds.Select(x=>x.Attribute("Id")).ToList();
      for(var i=0;i<ids.Count;i++)
        for(var j=i+1;j<ids.Count;j++)
          if(i!=j&&ids[i]==ids[j])
            _duplicateLeafs.Add(elementsWithIds.First(x=>x.Attribute("Id")==ids[i]));
      foreach(var subElement in elements)
        FindDupes(subElement);
    }
  }
}

Ответы [ 3 ]

2 голосов
/ 19 марта 2012

Вы говорите, что хотите проверить потомков уровня 2, но FindDupes рекурсивен, поэтому вы рекурсивно проверяете два уровня глубоко в циклах foreach, каждый вызов.

1 голос
/ 19 марта 2012
  1. В ваших циклах for храните список в переменной вместо доступа к свойству Count.

    для (int i = 0, idCount = ids.Count; i ++) { }

  2. Хранить идентификаторы [i] в ​​локальной переменной вместо того, чтобы искать их в коллекции более одного раза.

  3. Самым большим изменением было бы избегание вложенных циклов. Подумайте о переписывании.

Редактировать: внесены следующие изменения.

        private const string _pathToXml = @"C:\test.xml";
        private static readonly List<object> _duplicateLeafs = new List<object>();
        private static void Main()
        {
            var xml = ReadXml();
            var elements = xml.Descendants();
            FindDupes(elements);
        }

        private static void FindDupes(IEnumerable<XElement> elements)
        {
            foreach (var element in elements)
            {
                var subElements = element.Descendants();
                var subElementsWithIds = subElements.Where(x => x.Attribute("Id") != null).ToList();
                var ids = subElementsWithIds.Select(x => x.Attribute("Id")).ToList();
                var duplicates = ids.GroupBy(s => s.Value).SelectMany(grp => grp.Skip(1)).Distinct().ToList();

                if (duplicates != null)
                {
                    _duplicateLeafs.AddRange(duplicates);
                }
                FindDupes(subElements);
            }
        }

Использование следующего XML-файла:

<?xml version="1.0" encoding="utf-8" ?>
<persons>
  <person Id="1">
    <name>Michael</name>
    <age>29</age>
  </person>
  <person Id="1">
    <name>Rebecca</name>
    <age>29</age>
  </person>
  <person Id="2">
    <name>Matthew</name>
    <age>29</age>
  </person>
  <person Id="2">
    <name>Paul</name>
    <age>29</age>
  </person>
</persons>

После тестирования вашей последней версии и кода, который я предоставил, при загрузке файла 16 МБ вот время:

Time: 2.8704708 seconds Lambda solution
Time: 692.043006 seconds Nested for loops
1 голос
/ 19 марта 2012

вы повторяете проверку, поэтому вы можете сделать int j = i+1 вместо того, чтобы начинать с 0.

вам не нужно проверять i != j, затем

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...