Кодирование строки и использование len
для результата прекрасно работает, как показали другие ответы. Нужно создать одноразовую копию строки - если вы работаете с очень большими строками, это может быть неоптимально (хотя я не считаю 1024 байта большими большими ). Структура UTF-8 позволяет очень легко получить длину каждого символа, даже не кодируя его, хотя все еще может быть проще кодировать один символ. Здесь я представляю оба метода, они должны давать одинаковый результат.
def utf8_char_len_1(c):
codepoint = ord(c)
if codepoint <= 0x7f:
return 1
if codepoint <= 0x7ff:
return 2
if codepoint <= 0xffff:
return 3
if codepoint <= 0x10ffff:
return 4
raise ValueError('Invalid Unicode character: ' + hex(codepoint))
def utf8_char_len_2(c):
return len(c.encode('utf-8'))
utf8_char_len = utf8_char_len_1
def utf8len(s):
return sum(utf8_char_len(c) for c in s)
Разбейте его на множество простых запросов, а затем снова сложите эти запросы.
Начнем с создания последовательности элементов, совпадающих по имени:
var nameMatches = from item in itemList where item.Name == p.Name select item;
Нам нужно сравнить эти элементы с последовательностью имен в подэлементах p. Что это за последовательность? Напишите запрос:
var pnames = from subitem in p.SubItems select subitem.Name;
Теперь вы хотите найти все элементы из nameMatches, которым соответствует последовательность имен. Как вы собираетесь получить последовательность имен? Что ж, мы только что увидели, как это сделать с помощью pnames, поэтому сделайте то же самое:
var matches = from item in nameMatches
let subitemNames =
(from subitem in item.SubItems select subitem.Name)
where pnames.SequenceEqual(subitemNames)
select item;
А теперь вы хотите знать, есть ли совпадения?
return matches.Any();
Это должно работать нормально, как есть. Но если вы хотите стать настоящим фанатом, вы можете написать все в одном большом запросе!
return (
from item in itemList
let pnames =
(from psubitem in p.SubItems select psubitem.Name)
let subitemNames =
(from subitem in item.SubItems select subitem.Name)
where item.Name == p.Name
where pnames.SequenceEqual(subitemNames)
select item).Any();
И готово. Проще простого! Просто помните, разбейте его на маленькие шаги, решайте каждую проблему индивидуально, а затем составляйте решение из небольших результатов.
Если я правильно вас понял, вам нужен способ сравнения двух элементов, в котором вы сначала проверяете имена двух элементов, а затем последовательно проверяете имя каждого элемента. Вот что вы хотите:
public override bool Equals(object obj)
{
return this.Name == (obj as Item).Name;
}
public override int GetHashCode()
{
return this.Name.GetHashCode();
}
public bool Check(Item obj)
{
if (this.Name != obj.Name)
return false;
//if the lists arent of the same length then they
//obviously dont contain the same items, and besides
//there would be an exception on the next check
if (this.SubItems.Count != obj.SubItems.Count)
return false;
for (int i = 0; i < this.SubItems.Count; i++)
if (this.SubItems[i] != obj.SubItems[i])
return false;
return true;
}