Страницы

Поиск по вопросам

Показаны сообщения с ярлыком любой-язык. Показать все сообщения
Показаны сообщения с ярлыком любой-язык. Показать все сообщения

четверг, 9 апреля 2020 г.

Гибридное управление памятью

#память #любой_язык #сборщик_мусора

                    
В каком языке программирования можно комбинировать ручное управление памятью (в нужный
момент освободить, работа с указателями и так далее) и автоматическое, с достаточно
продвинутым сборщиком мусора по поколениям?

Иными словами, нужны две отдельные кучи для работы с памятью. 
    


Ответы

Ответ 1



Скорее всего вам подойдёт C++/CLI. Это Microsoft'овский гибрид C++ и платформы .NET. В нём .NET-объекты создаются при помощи gcnew и управляются сборщиком мусора, а стандартные C++-объекты создаются при помощи new и удаляются вручную через delete.

понедельник, 30 марта 2020 г.

Получение среднего цвета изображения

#любой_язык #цвета


Два дня тому назад, отключили интернет и пришлось быть без интернета. Вместо музыки
на сайте слушал приложение Windows "Музыка Groove". И тут я заметил интересную вещь:
приложение брало изображение саундтрека и аддитивным смещением  вычисляло средний цвет
всего изображения.


Саундтреки MARVEL были взяты для примера.
Как это можно реализовать? Подойдут решения на WPF, Windows Forms, ASP.NET или просто
на HTML/CSS/Javascript. 
    


Ответы

Ответ 1



Python-скрипт на основе примера из документации OpenCV: import cv2 import numpy as np from sklearn.cluster import KMeans from collections import Counter def get_dominant_color(image, k=4): image = image.reshape((image.shape[0] * image.shape[1], 3)) clt = KMeans(n_clusters=k) labels = clt.fit_predict(image) label_counts = Counter(labels) dominant_color = clt.cluster_centers_[label_counts.most_common(1)[0][0]] return list(dominant_color) bgr_image = cv2.imread('image.png') hsv_image = cv2.cvtColor(bgr_image, cv2.COLOR_BGR2HSV) dom_color = get_dominant_color(hsv_image) dom_color_hsv = np.full(bgr_image.shape, dom_color, dtype='uint8') dom_color_bgr = cv2.cvtColor(dom_color_hsv, cv2.COLOR_HSV2BGR) output_image = np.hstack((bgr_image, dom_color_bgr)) cv2.imshow('Dominant Color', output_image) cv2.waitKey(0)

Динамическое программирование в поиске чисел

#алгоритм #любой_язык #динамическое_программирование


На всех n-значных числах нужно посчитать кол-во таких чисел у которых любые две соседние
цифры имеют разность по модулю <= 1 
Допустим есть функция f(n) = кол-ву этих чисел 
Если для f(1) = 0, таких нет, для f(2) таких 8*3+2 (т.к. на промежутке 10-99 на всех
десятках есть по 3 таких числа, кроме числа начинающегося с 9 там их 2 т.к. оно крайнее,
например 10,11,12,21,22,23,32,33,34 ... 98,99.)
Получается что f(n) = f(n-1)*10 (т.к. если к изначально подходящему числу подставить
в конец любую цифру, то оно все равно удовлетворяет условию) + ..что то еще..
Долго не могу сложить этот пазл, как посчитать кол-во следующих n
    


Ответы

Ответ 1



Заполняем табличку. F - количество чисел длиной N, заканчивающихся цифрой L: F(N, L) {L=1..8} = F(N-1, L-1) + F(N-1, L) + F(N-1, L+1) F(N, 0) = F(N-1, 0) + F(N-1, 1) F(N, 9) = F(N-1, 9) + F(N-1, 8) F(1, 0) = 0 F(1, K>0) = 1

воскресенье, 15 марта 2020 г.

Алгоритм поиска в массиве двух максимальных значений

#алгоритм #массивы #любой_язык


В результате нужно получить индексы ячеек массива с максимальными значениями.

Например, для массива arr[4, 50, 11, 20] это будут 1 и 3 (arr[1], arr[3]) - индексы
максимальных значений.
    


Ответы

Ответ 1



Ну, почему бы не пробежаться по массиву и держать текущие k наибольших значений? Вот вам псевдокод: list maximalK = empty // инвариант: maximalK содержит отсортированный список наибольших // k из всех просмотренных элементов foreach e in sourceList p = position of e in maximalK // (binary search) if (p >= k) continue insert e into maximalK at position p if maximalK.size > k remove last from maximalK Заметьте, что при k == sourceList.size вы получаете просто алгоритм сортировки (бинарными) вставками. Временная сложность: O(n * k) (n — размер списка), за счёт сдвига при вставке. (Используя sorted map для maximalK, можно уменьшить до O(n * log k).)

среда, 4 марта 2020 г.

Дискретизация аналоговых значений

#алгоритм #любой_язык


Программа получает данные с датчика, измеряющего напряжение в вольтах.
Приходят целые значения в вольтах. Т.е. если на вход подать 1.9в, на выходе получаем
значение 1. А если на вход подать 2в, то получаем уже два.

Датчик имеет собственный шум (+/- 0.1 вольт) который складывается с измеряемым значением.

Это создает проблемы при входном напряжении, которое находится рядом с целыми значениями.
К примеру, если входное напряжение равно 2в, то в реальности будут замерены напряжения
1.9..2.1 (добавляются шумы), и показания будут скакать между 1 и 2. (хотя и ожидается
постоянное 2).

На рисунке синяя линия - вариант, когда входной сигнал далеко от границ целых значений,
и шум (неровность линии), не меняет результат. Красная линия - вариант, когда входной
сигнал на границе.

Конечному пользователю необходимо показать постоянное, не меняющееся значение.

Что было сделано:


усреднение значения за несколько замеров, не помогает, т.к. усредненное значение
также пляшет то в одну то в другую сторону
изменение конечного показания только при изменении входного больше чем на единицу,
помогает, то теряется точность и добавляется "люфт"




Какие ещё есть варианты решения, как вообще называются подобные проблемы перевода
аналоговых значений в цифровые (чтобы погуглить).

(Цифры упрощены, в реальности немного другие, суть не меняется)
    


Ответы

Ответ 1



Боюсь что тут вы ничего не поделаете, если у вас точность округления в единицу, то понятно, что при скачке на границе точности будет скакать и результат... Правда даже несмотря на то что датчик считает в целых числах, то среднее вы можете выдавать в дробных, тогда больших скачков уже не будет.

Ответ 2



В итоге сделал так. Делается некоторое кол-во замеров, получаем общее значение (дробное). Это позволяет убрать шум до какой-то степени, но пока еще просто округлять результат рано, т.к. на границе целых чисел будет все равно скакать итоговое значение. Далее, к полученному среднему значению (дробному) добавляется смещение в 0.2, в сторону, зависящую от предыдущего, конечного показания. После чего, сумма округляется и выдается конечному пользователю. Таким образом, чтобы "переключиться" в следующее, целое значение, нужно чтобы сигнал на входе изменился минимум на 0.2в, что больше чем шумы. Гуглил по "гистерезис". Так, примерно, работает терморегулятор на утюге (не постоянно щелкает, а переключается только при изменении температуры на значимое кол-во градусов).

Ответ 3



Почему бы не округлить? Например при диапазоне от нуля до единицы всё, что выше 0.707 округляется до единицы, а всё что меньше до нуля. У вас диапазон больше, и числа будут немного другие, но не суть важно.

суббота, 22 февраля 2020 г.

Исходный код в документации

#java #python #любой_язык #документация #javadoc


Можно ли в Javadoc указывать ссылку на исходный код классов и методов, чтобы не нужно
было каждый раз искать по каталогам нужный файл? Если да, то как это сделать? 

Вот пример для Python: документация SymPy содержит ссылки на исходники классов и методов.

Есть ли вообще какие-либо традиции для разных языков, каким способом публикуется
исходный код? Когда уместно прямо в документации выкладывать исходники, а когда достаточно
ссылки на Github?
    


Ответы

Ответ 1



У javadoc есть опция -linksource, которая включает исходный код в сгенерированную документацию. Например, в документации Guava есть ссылки на исходники в названиях классов и методов. Если код хранится в другом месте, можно использовать простую HTML ссылку .

воскресенье, 16 февраля 2020 г.

Исходный код в документации

#java #python #любой_язык #документация #javadoc


Можно ли в Javadoc указывать ссылку на исходный код классов и методов, чтобы не нужно
было каждый раз искать по каталогам нужный файл? Если да, то как это сделать? 

Вот пример для Python: документация SymPy содержит ссылки на исходники классов и методов.

Есть ли вообще какие-либо традиции для разных языков, каким способом публикуется
исходный код? Когда уместно прямо в документации выкладывать исходники, а когда достаточно
ссылки на Github?
    


Ответы

Ответ 1



У javadoc есть опция -linksource, которая включает исходный код в сгенерированную документацию. Например, в документации Guava есть ссылки на исходники в названиях классов и методов. Если код хранится в другом месте, можно использовать простую HTML ссылку .

пятница, 14 февраля 2020 г.

Удалить ненужные фотографии

#windows #изображения #любой_язык


Суть вопроса: есть 5000 фотографий, есть список в excel, точных названий нужных фотографий
(их 1000)

Как можно удалить все кроме этих 1000 фотографий? Не перерывая в ручную
    


Ответы

Ответ 1



Простейший путь - выделяем в Экселе нужный список файлов, Ctrl-C :), вставляем в обычном текстовом редакторе в файл, скажем, list.txt - чтоб по одному в строке. Дальше - одна команда for /F %f in (list.txt) do del /Q %f Примерно так... И никакого программирования не нужно :) Если имена файлов с пробелами - можно, например, воспользоваться ключом delims и кавычками - словом, смотрите, что напишет for /?... Но рекомендовал бы сначала убедиться, что все верно - for /F %f in (list.txt) do echo del /Q %f а то мало ли... Удаление - оно такое, не самое безопасное :) P.S. Простите за лирическое отступление - но, похоже, зря теперь не учат работать в командной строке, как когда-то во времена DOS с этого начинали... И даже Far или там FileCommander далеко не на каждой машине найдешь. А ведь просто в командной строке можно много что сделать...

Возможно ли переполнение при вычитании в компараторе?

#javascript #алгоритм #сортировка #любой_язык #переполнение


Рассмотрим сортировку, у которой в компараторе в качестве результата используется
разность сравниваемых элементов

a.sort((x, y) => x-y)


Очевидно, что при целочисленных типах данных этот алгоритм подвержен переполнению,
приводящему к неверному результату. Такой пример довольно лекго составить:



console.log([1<<31, 1].sort((x, y) => x-y|0))




А как насчёт вещественных чисел? Подвержены ли они проблеме переполнения?

Я могу придумать пример, где разность двух Infinity даёт NaN, но не могу придумать
ситуацию, в которой это бы сказалось на сортировке - ведь все бесконечности равны,
а разности с другими значениями поставят их на нужное место.



console.log([Infinity, 1, -Infinity, Infinity].sort((x, y) => x-y))



    


Ответы

Ответ 1



Представление целых чисел со знаком имеет зацикленную структуру за счет использования "дополнительного кода" для представления отрицательных значений. Это и является причиной того, что выполняя вроде бы обычное сложение двух целых чисел можно получить отрицательное число, если нет контроля переполнений, тоже касается сложения двух отрицательных. В представлении вещественных чисел (IEEE 754) цикличность отсутствует, знак числа хранится отдельным битом. Зато присутствует два нуля (+0, -0), собственно чтобы их не было и вводили дополнительный код в представлении целых. Переполнение мантиссы не возможно, т.к. из мантиссы вытесняются лишние младшие биты после вычисления порядка результата. Порядок хранится как целое без знака и его максимальное значение обрабатывается особым образом, поэтому вместо переполнения получаются либо бесконечности, либо NaN. Таким образом сам формат вещественных чисел (IEEE 754) не допускает ошибки переполнения при выполнении стандартных арифметических операций.

Ответ 2



Если для сортировки массива чисел с плавающей точкой использовать компаратор наподобие следующего (здесь и далее все примеры на C++): bool Compare(const double &a, const double &b) { return a - b > 0.0; } то проблемы возникнуть могут. Во-первых, массив исходных данных может содержать "нечисла" (Not-a-Number, NaN). NaN является неупорядоченным (unordered) по отношению к любым другим числам с плавающей точкой, включая самого себя. Это означает, что если по крайней мере один операнд бинарных операторов <, <=, ==, >=, > — NaN, то результат сравнения false; если по крайней мере один из операндов бинарного оператора != — NaN, то результат сравнения true (стоит заметить, что согласно стандарту вычислений с плавающей точкой IEEE 754-2008, операторы сравнения могут генерировать исключение в случае, если по крайней мере один из операндов — NaN). NaN также характеризуется особой арифметикой. Например, если по крайней мере один из операндов бинарного - — NaN, то результат NaN. Такие свойства NaN'ов в совокупности с представленным выше компаратором могут отрицательно сказаться на результатах сортировки. Для примера рассмотрим сортировку вставками (Пример): void InsertionSort(vector &vect) { for (size_t i = 1; i < vect.size(); ++i) for (size_t j = i; j > 0 && Compare(vect[j], vect[j - 1]); --j) swap(vect[j], vect[j - 1]); } Ни один элемент массива {1.0, NaN, 2.0, NaN, 1.0} после такой сортировки не будет перемещён. На каждой итерации цикла i при помощи функции Compare будет сравниваться пара чисел с плавающей точкой. И каждый раз в этой паре будет присутствовать NaN. И каждый раз результат сравнения будет false, а значит не будет произведено ни одного обмена элементов вектора. Второй пример связан с денормализованными (субнормальными) числами. Если бы удалось подобрать два таких числа a и b, что a > b, но a - b == 0, то возникли бы проблемы с сортировкой. Ведь a больше b, но компаратор говорит, что a не больше b, а значит алгоритм сортировки не обязан менять числа a и b местами. Википедия говорит, что в формате IEEE 754-2008 разность двух неравных, но близких друг к другу чисел, не бывает равна нулю. И обеспечивается это, отчасти, благодаря денормализованным числам. Взглянем повнимательнее на числа с плавающей точкой двойной точности. А именно на минимальное положительное нормализованное число (min), число следующее непосредственно за предыдущим (в сторону единицы, min_1), разность двух предыдущих (diff = min_1 - min) и минимальное положительное денормализованное число (denorm_min): min == 2.22507385850720138e-308 min_1 == 2.22507385850720188e-308 diff == 4.94065645841246544e-324 denorm_min == 4.94065645841246544e-324 Можно заметить, что разность двух нормализованных чисел представляет собой денормализованное значение. Некоторые процессоры (в частности, с поддержкой SSE2), позволяют сбрасывать до нуля (flush to zero) результат арифметического выражения, если он денормализованный. Т.е. в данном конкретном случае, разность двух нормализованных, неравных чисел min и min_1 вполне может получится равной нулю, а значит можно сконструировать пример некорректной сортировки. Воспользуемся Visual Studio, функцией _controlfp_s и напишем небольшой пример: #include #include #include #include #include #include using namespace std; #pragma fenv_access (on) bool Compare(const double &a, const double &b) { return a - b > 0.0; } int main() { double min = numeric_limits::min(); double min_1 = nextafter(min, 1.0); vector v = {min, min_1, min, 1.0, 2.0}; _controlfp_s(nullptr, _DN_FLUSH, _MCW_DN); sort(v.begin(), v.end(), Compare); for (auto val : v) cout << val << " "; cout << endl; } Вектор до сортировки: 2.22507385850720138e-308 2.22507385850720188e-308 2.22507385850720138e-308 1.0 2.0 Вектор после сортировки: 2.0 1.0 2.22507385850720138e-308 2.22507385850720188e-308 2.22507385850720138e-308 Хоть пример довольно таки надуманный, но не невозможный на практике (особенно с учетом того, что судя по документации, некоторые компиляторы по-умолчанию включают опцию flush to zero на всех уровнях оптимизации, больших чем -O0).

воскресенье, 9 февраля 2020 г.

Как поставить програмную точку останова

#отладка #любой_язык #faq


Как поставить програмную точку останова в разных языках средах и IDE. Часто вижу
вопросы не могу отладить программу потому что программа большая, обьёмы большие. Цикл
на 10000000. Такие ситуации можно отловить, например, при возникновении ошибки у меня
i=357489, а не понятно почему возникло исключение, тогда делаем, напимер так:

 for (i=0;i<10000000;i++) {
   if (i==357489) DebugBreak();
   // код
   }


Но DebugBreak - функция windows. Как можно поставить точки останова в других средах?
    


Ответы

Ответ 1



В с с++ есть такие варианты поставить точку останова DebugBreak(); - среда windows __builtin_trap() - среда linux raise(SIGTRAP) - работа с сигналами POSIX posix __EMIT__(0xCC) или __emit__(0xcc); - некоторые среды поддерживают вставку кода __asm { int 3;} или __asm { db 0xCC;} ассемблерная вставка Для других сред с# System.Diagnostics.Debugger.Break(); javascript debugger; java try {throw new TurnOnDebuggerException();}catch(TurnOnDebugger td) {/*Nothing*/ } pascal inline($CC); vbscript visual-basic stop

суббота, 8 февраля 2020 г.

Текстовые строки и NULL

#строки #null #любой_язык


Нынче вечер пятницы, поэтому мой вопрос не практического, а сугубо философского свойства,
для потрепаться. Каких-то материалов наверняка можно нагуглить, но гуглить неохота,
хочется поговорить.
Есть такая концепция — NULL-значения. Смысл: значение отсутствует, неизвестно, не
имеет смысла и т.п.
Если речь идёт, например, о дате рождения, то заданная дата — это дата рождения,
а NULL означает, что даты рождения гражданина мы по той или иной причине не знаем.
Ну или что он ещё не родился, сидит у мамы в животе.
При этом числовой 0 и NULL несут разную смысловую нагрузку. Если речь идёт, например,
о сумме денег на банковских счетах гражданина, то 0 может означать, что денег у него
нет, а NULL — что мы не знаем, сколько у него денег (не посчитали пока).
Во многих случаях NULL неприменим. Например, в банковском софте в записи о банковском
счёте сумма всегда известна точно — какой же это банк, если он сам не знает, сколько
на счёте денег?
Сказанное выше давно известно, это была прелюдия к вопросу. А вопрос такой:
Если у нас текстовое поле, то в каких случаях пустая строка и NULL несут разную смысловую
нагрузку?
Я думал и не смог придумать ни одного практически применимого примера. Складывается
впечатление, что пустой текст и NULL во всех случаях должны рассматриваться как эквиваленты.
Если позволить себе немного пофилософствовать, то я считаю, причина в том, что текст
— это очень особенный тип, в максимально общем виде выражающий древнюю, докомпьютерную
идею письменности. Вот у нас чистая восковая дощечка, на ней ни хрена нет, пусто. А
потом мы на ней чего-то накарябали стилом и теперь у нас есть текст. Легко заметить,
что «пустой текст» и «отсутствие текста» не различаются никак. Текст выпадает из состояния
«отсутствует» только тогда, когда в нём появляется хотя бы один символ.
Здесь уместно возразить, что NULL может обозначать отсутствие самой восковой дощечки,
однако, возвращаясь к информационным технологиям XXI века, хочется спросить: есть ли
примеры, где это нужно?
А что вы думаете про эквивалентность NULL-а и пустой строки? В каких случаях пустая
строка и NULL несут разную смысловую нагрузку?
Интересны любые примеры и соображения.
P.S. Речь, понятно, не только про классические SQL-СУБД, но про систему типов и значений
в целом, где бы она ни применялась.    


Ответы

Ответ 1



Да в куче случаев пустая строка и NULL могут иметь разный смысл. Например, текст инструкции. Если его не загрузили (еще не поместили в систему) -- NULL, а если просто сам текст отсутствует -- пустая строка. И позицию Oracle тоже понять можно. Все же SQL концептуально декларативный, а не процедурный язык, поэтому эквивалентность пустой строки и NULL может здорово облегчить жизнь разработчиков.

Ответ 2



Если у нас текстовое поле, то в каких случаях пустая строка и NULL несут разную смысловую нагрузку? Пустая строка - это строка, в которой нет символов. NULL - это вообще ничего. Если мы запросили перевод токена и получили пустую строку, значит токен непереводим. Если мы запросили перевод и результат - NULL, значит этим токеном никто не озаботился, и впору кидать эксепшен.

Ответ 3



Очень простой пример из жизни баз данных. База данных какой-нибудь больницы. Поле "отчество" допускает состояние пустоты >null<. Мы можем ничего не знать об отчестве от пациента (если он без сознания и без документов), тогда это >null<. И пациент по документам может не иметь отчества - ну, пусто у него в графе "отец". Или он принадлежит народности, где отчеств не бывает. Тогда в базу пишется не >null<, а пустая строка - мы знаем, что отчество есть, и знаем, что оно - пустое.

Ответ 4



NULL очень удобен именно как признак того, что у переменной вообще нет никакого значения, даже пустого. Например, для организации мемоизации. #include int main(void) { char* txt = NULL; for (int i = 0; i < 10; i++) { if (txt == NULL) { txt = "Hello World!"; } puts(txt); } return 0; }

Ответ 5



А в чём филосовское различие NULL(SQL) и null(нулевой указатель)? Судя по статье, в том, что операции сравнения по-разному определены. То есть NULL == NULL; // возвращает NULL или UNKNOWN null == null; // возвращает `true` Отсюда и филосовская разница для строк. Две пустые строки - одно и то же. Два значения NULL - разные вещи. Если надо проверить, что две строки (из внешних данных) равны, лучше использовать концепцию пустых строк, а не NULL.

Ответ 6



Когда из БД тянем несколько десятков параметров и объединяем их в одну строку, гораздо проще заранее сохранять их там (в случае отсутствия данных) в виде пустой строки (""), чем потом, перед объединением, каждый параметр проверять на то, что он не NULL. Dim fio As String = "Муслиев" & "Колабельды" & "" Меньше возни с исключениями...

среда, 5 февраля 2020 г.

Регулярное выражение для проверки строки версии (вроде 34.0.3, 23.2.*, 4.*)

#регулярные_выражения #строки #любой_язык


Нужно сделать регулярное выражение для проверки строки, обозначающей версию приложения.
Строка имеет вид X.Y.Z, где X, Y, Z могут быть любыми целыми числами, а также * (кроме
X). После символа * дальше строки быть не должно. Перед цифрами не должно быть 0.
Примеры валидных строк:


12.2323.2
0.0.3
0.0.0
34.0.3
23.2.*
4.*


Примеры неверных строк:


34а.34.1
*
34.*.3
57.*.
d3.43.3
0004.*
1.02.*


У меня такую регулярку сделать не вышло.

Это не учебное задание 
    


Ответы

Ответ 1



Наивная реализация того что вы хотите: ^(0|[1-9]\d*)\.(\*|(0|[1-9]\d*)\.(\*|(0|[1-9]\d*)))(\r)?$ Я получил ее следуя таким умозаключениям. Сперва составим регулярку, проверяющую строку на соответствие шаблону A.B.C, это просто: ^\d+\.\d+\.\d+(\r)?$ здесь \d+ - любая цифровая последовательность, \. - точка (надо экранировать, да), ^ - начало строки, (\r)?$ - конец строки, учитывающий как \r\n, так и просто \n Далее, вместо последнего блока цифр может стоять единственная звездочка, заменяем \d+ на (\*|\d+) (звездочку тоже надо экранировать): ^\d+\.\d+\.(\*|\d+)(\r)?$ Также звездочка может быть вместо последних двух блоков, аналогично предыдущему меняем \d+\.(\*|\d+) на (\*|\d+\.(\*|\d+)): ^\d+\.(\*|\d+\.(\*|\d+))(\r)?$ Ну и остается исключить числа с ведущими нулями, т.е. это либо отдельный ноль 0, либо не ноль + несколько любых цифр [1-9]\d*. Заменяем все три блока \d+ на конструкцию (0|[1-9]\d*), получаем окончательный вариант.

Ответ 2



^(0|[1-9]\d*)\.(\*|((0|[1-9]\d*)\.(\*|(0|[1-9]\d*))))$ Немного пояснений: ведущий ноль отсекаем таким выражением 0|[1-9]\d*. Т.е. разрешаем или один ноль, или цифру 1-9, а за ней любое количество любых цифр. * контролируем так \*|((0|[1-9]\d*)\.(\*|(0|[1-9]\d*))) или звездочка, или все остальное. Тест на regex101 https://regex101.com/r/41aBtQ/1

среда, 29 января 2020 г.

Алгоритм перехода в другую систему счисления

#алгоритм #любой_язык #системы_счисления


имеется следующий алфавит


  A=1; B=2; C=4;


Число 10, например, переводится как CCB, число 7 как CBA.
Как может выглядеть алгоритм, который преобразует число новую систему с наименьшим
числом символов (должно быть не AAAAA, а CA) На любом языке ответ приемлем, заранее
спасибо)
    


Ответы

Ответ 1



В данном случае вполне применим жадный алгоритм - сначала набираете делением с остатком наибольшие единицы (C), затем меньшие (B) и потом совсем малые(A). Типа 11 - сколько можно набрать C? только 2, итак - CC, остается 3. Его можно представить одним B с остатком 1 - итак, CCB и остаток 1 - т.е. A, так что окончательно - CCBA. Надо сказать, что такой жадный алгоритм годится не для всех наборов, но в вашем случае проходит. Думаю, закодировать проблемы быть не должно... P.S. Так, как вы сформулировали - это задача о размене, но не о переходе в другую систему счисления...

Ответ 2



Например на Питоне с использованием словаря алфавита: alph = {4: 'C', 2: 'B', 1: 'A'} x = int(input()) answ = '' Keys = list(alph.keys()) for k in Keys: a = x // k answ += a * alph[k] x -= a * k

Ответ 3



Просто опишу: дано число X Делим на цело Х на 4: d = X div 4 В результирующую строку вставляем d cимволов С Остаток от деления Х на 4: m = X mod 4 Берем остаток от деления m на 2: m1 = m mod 2 и частное d1 = m div 2 Если d1 равно 1, добавляем в результирующую строку В, если равно нулю, то ничего Если m1 равно 1, добавляем в результирующую строку A, если равно нулю, то ничего

Ответ 4



Решение на python-3.7: ALPH = {4: 'C', 2: 'B', 1: 'A'} def convert(num: int) -> str: assert num >= 1 new_num = '' for key in ALPH: while num >= key: num -= key new_num += ALPH[key] return new_num print(convert(int(input()))) Тесты: print(convert(11)) # CCBA print(convert(10)) # CCB print(convert(7)) # CBA

вторник, 28 января 2020 г.

Слияние отрезков

#алгоритм #любой_язык


На входе есть список отрезков какой-то (непрерывной) оси (числовой или временной,
не важно), каждый отрезок представлен парой (упорядоченных) координат — начало и конец
(эти точки также принадлежат отрезку).

Необходимо слить все пересекающиеся отрезки и получить на выходе список отрезков
не имеющих пересечений (но этот новый список не должен иметь точки, которых не было
в отрезках на входе).

Например, имеем на входе:

[1; 5]
[2; 4]
[7; 9]
[3; 6]


тогда, на выходе необходимо получить:

[1; 6] // здесь слиты [1; 5], [2; 4], [3; 6]
[7; 9]


реализовал алгоритм примерно такой:



function merge(segments) {
  while (true) {
    const newSegments = [];
    for (const x of segments) {
      let found = false;
      for (const y of newSegments) {
        if (x.end >= y.start && x.start <= y.end) {
          y.start = Math.min(y.start, x.start);
          y.end = Math.max(y.end, x.end);
          found = true;
          break;
        }
      }
      if (!found) newSegments.push(x);
    }
    if (segments.length == newSegments.length) break;
    segments = newSegments;
  }
  return segments;
}

function print(segments) {
  console.log(segments.map(s => `[${s.start}; ${s.end}]`).join(' '));
}

let segments = [
  { start: 1, end: 5 },
  { start: 2, end: 4 },
  { start: 7, end: 9 },
  { start: 3, end: 6 }
];

print(segments);
print(merge(segments));




Он работает, но имеет сложность O(n³).
Можно ли написать решение лучше?

Есть идея: отсортировать входной список и как-то адаптировать метод сканирующей прямой;
но как это реализовать пока не могу придумать.
    


Ответы

Ответ 1



Сортировка по левой точке - это правильный первый шаг, получаем: [1; 5] [2; 4] [3; 6] [7; 9] Далее сравниваем первый отрезок со вторым - начало второго попадает в первый отрезок, значит сливаем отрезки: началом будет начало первого, а концом - max(конец первого, конец второго), получаем [1; 5]. [1; 5] [3; 6] [7; 9] Так же сливаем [1; 5] и [3; 6] в [1; 6] [1; 6] [7; 9] [1; 6] и [7; 9] не пересекаются, значит фиксируем [1; 6] с ним уже никакой другой отрезок не пересечется, и повторяем все действия начиная с [7; 9] сложность сортировки O(n log(n)), сложность слияния O(n) итого O(n log(n))

Ответ 2



Получилось в итоге так: function merge(segments) { if (segments.length === 0) return []; const inp = segments.map(s => ({...s})); inp.sort((a, b) => a.start - b.start); const out = []; let s = inp[0]; for (let i = 1; i < inp.length; ++i) { if (inp[i].start <= s.end) { s.end = Math.max(s.end, inp[i].end); } else { out.push(s); s = inp[i]; } } out.push(s); return out; } function print(segments) { console.log(segments.map(s => `[${s.start}; ${s.end}]`).join(' ')); } let segments = [ { start: 1, end: 5 }, { start: 2, end: 4 }, { start: 7, end: 9 }, { start: 3, end: 6 } ]; print(segments); print(merge(segments));

Ответ 3



больше от скуки запилил решение на C# public class Solution { public int[][] Merge(int[][] intervals) { if (intervals == null || intervals.Length == 0) return new int[0][]; Array.Sort(intervals, 0, intervals.Length, new IntervalComparer()); var stack = new Stack(); var curr = intervals[0]; for(int i=1; i= next[0]) curr = new int[] {curr[0], Math.Max(curr[1], next[1])}; else { stack.Push(curr); curr = next; } } stack.Push(curr); var ret = new int[stack.Count][]; for(int i = ret.Length-1; i>=0; i--) ret[i] = stack.Pop(); return ret; } private class IntervalComparer : IComparer { public int Compare(int[] x, int[] y) { return x[0].CompareTo(y[0]); } } } Этот код побил 99.7% решений этой задачи на leetcode (решений на C#)

Ответ 4



const merge = ss => { ss = ss.sort((a, b) => a.start - b.start) let c = ss.shift() const m = [c] ss.forEach(s => (s.start <= c.end) ? (s.end > c.end) && (c.end = s.end) : m.push(c = s)) return m } console.log(merge([ { start: 1, end: 5 }, { start: 2, end: 4 }, { start: 7, end: 9 }, { start: 3, end: 6 } ]))

Языки программирования - разница в комментах в зависимости от позиции в строке

#любой_язык #комментарии


Помогите пожалуйста с нахождением языка, на котором есть синтаксическое различие
между определение коммента в начале строки и определением в середине строки ? 
    


Ответы

Ответ 1



VB6 В начале: Rem я комментарий ' я тоже комментарий А в середине - только такой ЯКакойТоКод ' а я комментарий Javascript, только для браузеров (ES6, Annex B) В начале строки: // Комментарий и это - тоже В середине - только так: doSmth(); // комментарий doSmthElse(); как и это НоВотТут --> СноваКод // А так - нет КакИТут // тоже можно }

Ответ 2



В Фортране такое было (в конце концов, был заявлен же "любой язык" :) ), например: C - Комментарий, начинающийся с этого символа, мог располагаться только в начале строки; ! - Комментарий, начинающийся с этого символа, мог начинаться с любой позиции.

Ответ 3



Все банально, Java int a = 1; int b = 2; //int c = 3; if (a < b /*&& b < c*/) { //TODO: } Я правильно вас понял?

воскресенье, 26 января 2020 г.

О чем должен говорить комментарий в коде?

#любой_язык #code_style


О чем должен говорить комментарий в коде? О том, что происходит в следующем блоке
кода или о том, что должно произойти в результате выполнения этого блока кода? Что
в этом вопросе подсказывает/требует практика?
    


Ответы

Ответ 1



Хороший комментарий — ненаписанный комментарий. Следует стремиться писать код так, чтобы комментарии были просто не нужны. Проблема комментариев в том, что часто они находятся в одном месте, а помнить о них их нужно в другом компилятор не может проверить истинность комментария, поэтому при изменении кода комментарий устаревает Пройдёмся по часто встречающимся случаям, в которых комментарии излишни. Если вы хотите прокомментировать, для чего нужна какая-то переменная, выбросьте комментарий, и измените имя переменной на более подходящее. int n; // количество страусов лучше заменить на int numberOfOstriches; Если вы хотите сообщить, что выполняется какое-то условие, лучше поставить assert: // тут pBFG не может быть nullptr-ом, проверка не нужна pBFG->fire(); лучше заменить на assert(pBFG); pBFG->fire(); Если вы описываете в комментарии, что именно делает кусок кода, имеет смысл вместо этого выделить этот кусок в отдельную функцию, а смысл кода сделать её именем. // нормализовать вектор скорости double temp_length = sqrt(velocity.x * velocity.x + velocity.y * velocity.y); velocity.x /= temp_length; velocity.y /= temp_length; лучше заменить на void Normalize(vector& v) { double length = sqrt(v.x * v.x + v.y * v.y); if (length == 0.0) throw argument_exception("zero length vector"); v.x /= length; v.y /= length; } Normalize(velocity); Если вы описываете в комментарии самоочевидные вещи, лучше этот комментарий просто выкинуть. // этот класс представляет точку class Point { public int X; // координата X public int Y; // координата Y } ни капли не теряет в читаемости в таком виде: class Point { public int X; public int Y; } (а если бессмысленные комментарии требуются от вас стандартами кодирования, потребуйте изменения этих стандартов!) Таким образом, что происходит в участке кода, должно быть по возможности понятно из самого куска кода. Если это не так — улучшайте его. Если комментарий представляет собой на деле документацию к вашему коду, тут ничего не поделаешь, удалять его не нужно. Те немногие места, где комментарии действительно нужны — описания используемых алгоритмов, оптимизаций, документация багфиксов и неочевидных решений. Здесь снова-таки старайтесь писать о том, почему вы делаете так, как делаете. А как именно вы делаете, должно быть понятно из кода.

Ответ 2



"Ну ты, барин, и задачи ставишь"... (с) К/ф "Формула любви" К комментариям нет требований. Понимаете, это все равно как спросить - рассказ должен описывать намерения автора или действия персонажей? Сама постановка странная - что именно писать в комментарии... А уж различать "что происходит" и "что должно произойти" - это уж совсем странно. Вообще-то код нужно писать так, чтоб он сам по себе комментировал, что он делает. Придумано не мной, но я с этим, в общем-то, согласен. И уж точно не нужно комментировать в духе "присваиваем переменной сумму двух других" :) Пишите комментарии так, чтобы вы через год-два могли глянуть на код и разобраться, что же он делает. Отдельно я бы выделил комментарии о том, что надо не забыть сделать :) Если работаете в команде - то работайте так, как решено командой. Под конец процитирую Саттера: Не предписывайте стиль комментариев (кроме тех случаев, когда специальный инструментарий использует их для документирования), но пишите только нужные и полезные комментарии. Вместо комментариев пишите, где это возможно, код.

Ответ 3



Хорошие комментарии именно в коде (а не перед функциями и т.п.) должны пояснять зачем этот кусок нужен для решения задачи. Вполне вероятно, что для понимания этого "зачем", потребуется описать состояние исходных данных и что получается после выполнения комментируемого кода. А как именно это реализуется, желательно рассказывать самим кодом.

среда, 22 января 2020 г.

Какие есть способы предупреждения ошибок, их нахождения и устранения?

#отладка #любой_язык #обработка_ошибок


При разработке часто могут возникать разного рода ошибки, а у меня нет знаний о том
как и с помощью чего можно было бы их обнаруживать или упреждать. Даже мелкие ошибки.
Поэтому часто задаю вопросы в формате "Где ошибка в коде?" на разных ресурсах, вместо
того, чтобы самостоятельно всё исправить.

Так как общие инструменты и практики есть во всех языках, то хотелось бы все их узнать,
от простых до сложных. Напишите, пожалуйста, какие способы есть?

Спасибо.
    


Ответы

Ответ 1



Мой ответ будет про IDE. IDE (англ. Integrated Development Environment - Интегрированная среда разработки). Их очень много. Например часто используют: для c# — Visual Studio для javascript — WebStorm, NetBeans, Eclipse, Brackets, Sublime и т.д. для php — PHPStorm, NetBeans, Eclipse и т.д. для java — Intellij IDEA для других языков еще что-то В IDE много бесконечных возможностей, например: детектор дублируемого кода рефакторинг инструменты для работы с базами данных интеграция с системами управления версиями автодополнение кода подсветка синтаксиса подсказки при наборе кода (функции, ключевые слова, переменные, которые объявлял ранее) и многое другое Как это поможет? Среда знает, что она редактирует код и знает язык, на котором написан код. В неё встроен синтаксический анализатор языка программирования. Еще на самом первом этапе написания кода она может показать строки с банальными (и не только) ошибками, но которые уже могут привести к нерабочему или неправильно функционирующему коду. IDE показывает номер строки кода, где предположительно ошибка; краткое и полное описание ошибки, которое можно прочитать, проанализировать и исправить. Ошибки показываются как на боковой панели, так и в самом редакторе еще на этапе написания, а для компилируемых языков еще и в консоли при запуске программы. Примеры: Visual Studio Intellij IDEA WebStorm и PHPStorm Можно сразу видеть: уровень ошибки (предупреждение, уведомление, ошибка) полный текст ошибки в каком файле номер строки, на которой ошибка Можно перейти в скрипт на указанную строку и проанализировать. Не знаете английский? Откройте любой онлайн переводчик и скопируй туда текст ошибки заменив заглавные буквы на строчные: C# CS0103 The name 'getSum' does not exist in the current context ConsoleApp2017 C:\VS\ConsoleApp2017\Program.cs 6 Имя «getSum» не существует в текущем контексте ConsoleApp2017 в файле C:\VS\ConsoleApp2017\Program.cs На линии №6 Не может найти метод getSum в классе Program.cs на линии 6. Значит вызов есть, а объявления нет и искать надо в указанном направлении. Java Error:(34, 9) java: cannot find symbol symbol: method getSum() location: class test.Test Ошибка: (34, 9) java: не удается найти символ Символ: метод getSum () Местоположение: класс test.Test и так далее. Исправлять желательно все ошибки, как минимум уровня опасности "красный". warning и notice могут быть временно забыты, например сообщение о неиспользованной переменной, которую вы точно намерены потом использовать. Но в итоге надо починить их все! В IDE еще много полезных и не упомянутых возможностей. Для их использования: - определись с языком, подбери нужную IDE и изучай.

Можно ли, используя SQLite, обращаться к таблицам из разных файлов?

#delphi #sqlite #любой_язык


Используя MySQL, я могу обращаться к таблицам из разных схем. Например, работая с
MySQL в Delphi через ADO, несмотря на то, что я явно задаю схему по умолчанию (в данном
случае - dna_homo_2015may):

var
  ADO1:TADOConnection;

<...>
ADO1.ConnectionString:='Provider=MSDASQL.1;Password=password;'+
   'Persist Security Info=True;User ID=user1;Extended Properties="Driver=MySQL ODBC
5.3 ANSI Driver;'+
   'SERVER=localhost;UID=user1;PWD=password;DATABASE=dna_homo_2015may;'+
   'PORT=3306;COLUMN_SIZE_S32=1"';


я могу обращаться к таблицам из нескольких схем, указывая их имена полностью:

Query:='select A.*, B.`id`, B.`name`'+
    'from `dna_homo_2015may`.`temp_pos` A, `dna_homo_2016june`.`genes_list` B'+
    'where <...>';


Могу я, используя SQLite и имея две таблицы table1 в файле base1.sdb  и table2 в
файле base2.sdb, выполнить аналогичный запрос, с одновременной выборкой из этих двух
таблиц? Если да, то как? 
    


Ответы

Ответ 1



Отвечу, в итоге, сам. Можно, и не одним способом, хотя все они отличаются инструментами реализации, а не подходом. Я испробовал ADO, FireDAC, объектный враппер, непосредственную работу с SQLite3.DLL и даже триальные компоненты от DevArt. Скажу сразу - через ADO использовать два разных файла в качестве поставщиков таблиц не получится. У меня, по крайней мере, так и не получилось. Все остальные инструменты более или менее работают. Вся соль заключалась в том, что несмотря на начальное обращение к файлу таблицы (привожу пример с использованием враппера) s:='P:\SQLLite_DBs\hg38-genes.sdb.db'; base:=TSQLiteDatabase.Create(s); с последующим аттачем второй базы s:= 'attach `P:\SQLLite_DBs\hg38-repeats.sdb.db` as db2;'; base.ExecSQL(s); ещё раз инициализировать первую таблицу, уже как db1: s:= 'attach `P:\SQLLite_DBs\hg38-genes.sdb.db` as db1;'; base.ExecSQL(s); Всё. Теперь можно смело обращаться к разным таблицам из разных файлов: s:='select b.id from db1.`genes-g38-201505` a, db2.`repeats-g38` b where a.`chr` = b.`chr`;'; tb:=base.GetTable(s); Чтобы обращаться к таблицам из разных файлов. То же самое и с остальными способами работы с SQLite. Однако, провозившись несколько вечеров с SQLite, я понял, что придётся отказаться от её использования: несмотря на все ухищрения, она уступает в скорости MySQL и не может работать с огромными объёмами данных на уровне геномов. Особенно это касается работы через враппер - он писался не для работы в 64-битном режиме. А жаль: хотелось бы избавиться от обязательного наличия MySQL-сервера и инструкций, как обновлять базы.

Нарисовать обводку эллипса

#алгоритм #графика #любой_язык


Как можно точно и быстро нарисовать обводку эллипса в канонической форме заданной
толщины? При этом используя только треугольники или отдельные пиксели. 

Сам-то эллипс можно, например, с помощью алгоритма Брезенхема или Midpoint circle,
а для обводки так сразу ничего не нашёл. Может быть, можно как-нибудь применить параметрические
уравнения обводки (двух её границ):



Здесь (x0, y0) точка на эллипсе, h — толщина обводки (больше 0 — внешняя, меньше
— внутренняя).

Обновление

Обводка эллипса — это область чёрного цвета на этом рисунке.



var a_canvas = document.getElementById("a");
var ctx = a_canvas.getContext("2d");

ctx.lineWidth = 20;
ctx.beginPath();
ctx.ellipse(100, 100, 50, 70, 0, 0, 2 * Math.PI);
ctx.closePath();
ctx.stroke();




  
  






    


Ответы

Ответ 1



Жирный эллипс - дело нехитрое. Берем неявно заданное уравнение эллипса: F= x^2/a^2 + y^2/b^2 + z^2/c^2 = R^2 Для этого уравнения берем вектор нормали: N{2x/a^2; 2y/b^2; 2z/c^2;} Нормируем N, путем деления на длину. В каждой точке X нашей области, где сидит наш эллипс, проверяем, что: F( X + e*N) * F(X - e*N) < 0 e - половина толщины обводки X - координаты текущей точки Если условие выполняется, рисуем черный пиксел

Ответ 2



Придумал такой алгоритм. Можно построить две кривые — границы обводки, и всё, что между ними, закрасить. Эти кривые — эквидистанты, они равноудалены от эллипса. Для построения кривых можно использовать Midpoint-алгоритм, подобно тому, как это делается для эллипса и круга. Правда, оптимизировать его аналогичным образом мне не удалось. Уравнение сразу двух кривых в форме f(x,y) = 0 я взял отсюда (теорема 3). Точки, где производная равна единице, можно найти, подставив точку эллипса, где производная единица, в уравнения в вопросе. Дополнительно, для внутренней эквидистанты, нужно найти точки пересечения функции и OY и начинать алгоритм не с (a-h, 0), а с одной из точек, как только две точки пересечения совпадут. Можно строить эквидистанты только для эллипсов с a >= b, иначе поворачивать построенные кривые. В этом коде строятся только границы обводки: const CHANNELS_PER_PIXEL = 4; function calcFunc(x, y, a, b, h) { var a1 = a * a + b * b - x * x - y * y + h * h; var a2 = a * a * b * b - b * b * x * x - a * a * y * y + h * h * (a * a + b * b); var a3 = h * h * a * a * b * b; var a312 = a3 / a1 / a2; return 1 - 4 * a2 / a1 / a1 - 4 * a1 * a3 / a2 / a2 + 18 * a312 - 27 * a312 * a312; } function drawOutline(x0, y0, a, b, h, canvas) { var imageWidth = canvas.width; var imageHeight = canvas.height; var context = canvas.getContext('2d'); var imageData = context.getImageData(0, 0, imageWidth, imageHeight); var pixelData = imageData.data; var makePixelIndexer = function (width) { return function (i, j) { var index = CHANNELS_PER_PIXEL * (j * width + i); return index; }; }; var pixelIndexer = makePixelIndexer(imageWidth); var drawPixel = function (x, y, col) { var r = (col >> 16) & 255; var g = (col >> 8) & 255; var b = col & 255; var idx = pixelIndexer(x, y); pixelData[idx] = r; pixelData[idx + 1] = g; pixelData[idx + 2] = b; pixelData[idx + 3] = 255; }; var swap = false; if(b > a){ swap = true; var t = a; a = b; b = t; } var draw4Pix = function(x, y, col){ if(swap) { drawPixel(x0 - y, y0 - x, col); drawPixel(x0 - y, y0 + x, col); drawPixel(x0 + y, y0 - x, col); drawPixel(x0 + y, y0 + x, col); } else { drawPixel(x0 - x, y0 - y, col); drawPixel(x0 - x, y0 + y, col); drawPixel(x0 + x, y0 - y, col); drawPixel(x0 + x, y0 + y, col); } }; var x = a + h; var y = 0; var lastX = a * a / Math.sqrt(a * a + b * b) + h / Math.sqrt(2); var prevX; while (true) { draw4Pix(x, y, 0xFF0000); y++; if (calcFunc(x - 0.5, y + 1, a, b, h) > 0) { x--; } if (x < lastX) { draw4Pix(x, y, 0xFF0000); prevX = x; break; } } if(prevX != 0) { x = 0; y = b + h; while (true) { draw4Pix(x, y, 0xFF0000); x++; if (calcFunc(x + 0.5, y - 1, a, b, h) > 0) { y--; } if (x >= prevX) { draw4Pix(x, y, 0xFF0000); break; } } } if(h < a && h < b){ lastX = a * a / Math.sqrt(a * a + b * b) - h / Math.sqrt(2); var root = (Math.sqrt(a*a - b*b) * Math.sqrt(b*b - h*h))/b; if(h > b*b / a){ x = Math.ceil(root); } else { x = a - h; } y = 0; if(x > lastX) { while (true) { draw4Pix(x, y, 0x0000FF); y++; if (calcFunc(x - 0.5, y + 1, a, b, h) < 0) { x--; } if (x < lastX) { draw4Pix(x, y, 0x0000FF); prevX = x; break; } } } else { prevX = Math.floor(root); draw4Pix(x, y); } if (prevX != 0) { x = 0; y = b - h; while (true) { draw4Pix(x, y, 0x0000FF); x++; if (calcFunc(x + 0.5, y - 1, a, b, -h) < 0) { y--; } if (x >= prevX) { draw4Pix(x, y, 0x0000FF); break; } } } } context.putImageData(imageData, 0, 0); } function ellipseAndOutline(x0, y0, a, b, h, drawEllipse, canv){ drawOutline(x0, y0, a, b, h, canv); if(drawEllipse) { var ctx = canv.getContext('2d'); ctx.beginPath(); ctx.lineWidth = 1; ctx.ellipse(x0, y0, a, b, 0, 0, Math.PI * 2); ctx.closePath(); ctx.stroke(); } } document.getElementById('btn').onclick = function () { var canv = document.getElementById('canv'); var ctx = canv.getContext('2d'); ctx.clearRect(0, 0, canv.width, canv.height); ellipseAndOutline( canv.width / 2, canv.height / 2, parseInt(document.getElementById('aInp').value), parseInt(document.getElementById('bInp').value), parseInt(document.getElementById('hInp').value), document.getElementById('drawEllCh').checked, canv); }
a b h эллипс


Как проверять слова Русского языка?

#разработка_игр #поиск #любой_язык #словари


Для игры типа «Эрудита» надо проверять, есть ли составленное игроком слово в словаре,
и соответствует ли оно требованиям: именительный падеж, единственное число.
Наверное, достаточно раздобыть текстовый файл со словами через разделитель, и в нём
искать. Кстати, может, есть некий формат, более удобный для поиска? Дерево, сортировка,
всё такое?
Основной вопрос — как расширить набор правил? Разрешить, например, все падежи, множественное
число, глаголы во всех временах.     


Ответы

Ответ 1



На мой взгляд, какого-то лёгкого или средней сложности способа вы врядли найдёте. Разве что, пропишите все возможные варианты в БД или файле. С падежами - проще. Можно было бы прописать корни слов и отдельно возможные суфиксы, окончания слов и т.д. Но и тут засада. Возьмём для примера слова "хэшкод" и "конь". Как проверить правильность написанных слов, если в дательном падеже первое слово будет "хэшкодУ", а второе - "конЮ"? Вопрос риторический. С глаголами и их временами ещё печальней. Берём: "ехать" и "идти". В неопределенном времени (1-е лицо) получаем "езжу" и "хожу". Тут даже логики не просматривается. Вывод: "Велик и могуч русский язык, но под PHP не заточен". P.S. Кстати, тут неподалеку есть еще один форум (Русский язык). Возможно, что там могут кое-что дельное подсказать.

Ответ 2



Я думаю стоит конвертировать словарь в отдельную SQL таблицу для каждой части речи: Например для имен существительных могут быть такие поля: ID, Приставка, Корень, Суффикс, Окончание, Падеж, Род, Все слово, Одушевлённость, Число(единственное множественнно),Склонение, Нарицательность, Это же слово по умолчанию(ед число именительный падеж) И далее просто делать SELECT к этой таблице. Другой вопрос как получить эту таблицу из текстового файла, придется писать очень нетривиальный парсер учитывающий морфологию.