Сравнение рубиновых хешей [дубликат]

Обратите внимание, что в вышеупомянутых решениях для C++, были некоторые проблемы.

Одно решение было неэффективно, потому что оно передало станд.:: строка копией, и потому что это выполнило итерации по всем символам, вместо того, чтобы сравнить только половину символов. Затем даже когда обнаружение строки не было палиндромом, это продолжало цикл, ожидая его конец прежде, чем сообщить о "лжи".

другой было лучше, с очень небольшой функцией, проблема которой состояла в том, что она не смогла протестировать что-либо еще, чем станд.:: строка. В C++ легко расширить алгоритм до целого набора подобных объектов. Путем шаблонной обработки его станд.:: строка в "T", это работало бы над обоими станд.:: строка, станд.:: wstring, станд.:: вектор и станд.:: двухсторонняя очередь. Но без основной модификации из-за использования оператора < станд.:: список был вне его объема.

Мои собственные решения пытаются показать, что решение для C++ не остановится при работе над точным текущим типом, но будет стремиться работать что-либо , который ведет себя тот же путь, неважно, тип. Например, я мог применить свои тесты палиндрома на станд.:: строка, на векторе интервала или в списке "Чего-либо", пока Что-либо было сопоставимо через его оператор = (сборка в типах, а также классы).

Примечание, что шаблон может даже быть расширен с помощью дополнительного типа, который может использоваться для сравнения данных. Например, если Вы хотите выдержать сравнение нечувствительным к регистру способом, или даже сравнить подобные символы (как ГЁ, Г©, Г «, ГЄ и e).

Как король Leonidas сказал бы: "Шаблоны? Это - C++!!!"

Так, в C++, существует по крайней мере 3 главных способа сделать это, каждый ведущий к другому:

Решение A: подобным c способом

проблема состоит в том, что до C++ 0X, мы не можем рассмотреть станд.:: массив строк символов как непрерывные, таким образом, мы должны "обмануть" и получить c_str () свойство. Поскольку мы используем его способом только для чтения, это должно быть в порядке...

<час>
bool isPalindromeA(const std::string & p_strText)
{
   if(p_strText.length() < 2) return true ;
   const char * pStart = p_strText.c_str() ;             
   const char * pEnd = pStart + p_strText.length() - 1 ; 

   for(; pStart < pEnd; ++pStart, --pEnd)
   {
      if(*pStart != *pEnd)
      {
         return false ;
      }
   }

   return true ;
}
<час>

Решение B: больше версии

"C++" Теперь, мы попытаемся применить то же решение, но к любому контейнеру C++ с произвольным доступом к его объектам через оператор []. Например, любой станд.:: basic_string, станд.:: вектор, станд.:: двухсторонняя очередь, и т.д. Оператор [] является постоянным доступом для тех контейнеров, таким образом, мы не потеряем неуместную скорость.

<час>
template <typename T>
bool isPalindromeB(const T & p_aText)
{
   if(p_aText.empty()) return true ;
   typename T::size_type iStart = 0 ;
   typename T::size_type iEnd = p_aText.size() - 1 ;

   for(; iStart < iEnd; ++iStart, --iEnd)
   {
      if(p_aText[iStart] != p_aText[iEnd])
      {
         return false ;
      }
   }

   return true ;
}
<час>

Решение C: Шаблон powah!

Это будет работать почти с любым незаказанным подобным STL контейнером с двунаправленными итераторами, Например, любым станд.:: basic_string, станд.:: вектор, станд.:: двухсторонняя очередь, станд.:: список, и т.д. Так, эта функция может быть применена на все подобные STL контейнеры со следующими условиями: 1 - T является контейнером с двунаправленным итератором 2 - итератор T указывает на сопоставимый тип (через оператор =)

<час>
template <typename T>
bool isPalindromeC(const T & p_aText)
{
   if(p_aText.empty()) return true ;
   typename T::const_iterator pStart = p_aText.begin() ;
   typename T::const_iterator pEnd = p_aText.end() ;
   --pEnd ;

   while(true)
   {
      if(*pStart != *pEnd)
      {
         return false ;
      }

      if((pStart == pEnd) || (++pStart == pEnd))
      {
         return true ;
      }

      --pEnd ;
   }
}
<час>
32
задан Community 23 May 2017 в 12:17
поделиться

2 ответа

Если все, что вас волнует, это уникальность element2, вы можете просто сделать:

element2.to_a - element1.to_a
11
ответ дан 27 November 2019 в 20:28
поделиться

Изменить:

Я постоянно возвращаюсь к этому коду, чтобы использовать его в проектах, над которыми я работаю. Вот последняя версия, которая полезна для глубоко вложенных структур и основана на приведенном выше коде Пита. Обычно я помещаю его в config / initializers / core_ext.rb (в проекте Rails):

class Hash
  def deep_diff(other)
    (self.keys + other.keys).uniq.inject({}) do |memo, key|
      left = self[key]
      right = other[key]

      next memo if left == right

      if left.respond_to?(:deep_diff) && right.respond_to?(:deep_diff)
        memo[key] = left.deep_diff(right)
      else
        memo[key] = [left, right]
      end

      memo
    end
  end
end

class Array
  def deep_diff(array)
    largest = [self.count, array.count].max
    memo = {}

    0.upto(largest - 1) do |index|
      left = self[index]
      right = array[index]

      next if left == right

      if left.respond_to?(:deep_diff) && right.respond_to?(:deep_diff)
        memo[index] = left.deep_diff(right)
      else
        memo[index] = [left, right]
      end
    end

    memo
  end
end

Вот небольшая демонстрация:

> {a: [{b: "c", d: "e"}, {b: "c", f: "g"}]}.deep_diff({a: [{b: "c", d: "e"}, {b: "d", f: "g"}]})
=> {:a=>{1=>{:b=>["c", "d"]}}}

Старый ответ:

Я обнаружил, что метод Rails Hash diff не говорит мне, что был слева и справа (что гораздо полезнее). Был исчезнувший с тех пор плагин с названием "Riff", который позволял вам различать два объекта ActiveRecord. По сути:

class Hash
  def diff(other)
    self.keys.inject({}) do |memo, key|
      unless self[key] == other[key]
        memo[key] = [self[key], other[key]] 
      end
      memo
    end
  end
end
20
ответ дан 27 November 2019 в 20:28
поделиться
Другие вопросы по тегам:

Похожие вопросы: