Разное

Дерево из спичек: Потрясающее дерево из спичек. Легко сделали и быстро сожгли! | Творческие идеи

Содержание

Поделки из спичек своими руками

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

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

Спички являются одним из тех обычных подручных материалов, которые могут  превратиться в невероятные красивые произведения искусства. Давайте посмотрим!

Снежинка из спичек своими руками

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

Домик из спичек своими руками

Очень красивая поделка, которая обязательно понравится детям. Миниатюрный домик из спичек выглядит очень интригующе, так и хочется заглянуть в окошко.

Объемные картины из спичек

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

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

 

 

Деревья из спичек

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

Ожерелье и браслет из спичек

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

Автомобиль из спичек

Удивительная работа, которая поражает своей точностью и терпением мастера. Эта изумительная модель спортивного автомобиля из обыкновенных спичек достойна самого почетного места на полке.

Браслеты из спичек

Эта красивая и уникальная пара браслетов, состоящая из спичек, является удивительным произведением искусства и необыкновенным дополнением к вашим аксессуарам. Розовый цвет делает этот аксессуар привлекательным и подходит для девочки-подростка.

Цветок из спичек и бумаги тишью

Вы не должны ограничивать свое творчество только спичками. Пробуйте комбинировать спички с другими материалами.

Курица из спичек

Удивительная курица, которая состоит из одни только спичек. Такая подлека отлично впишется в интерьер кухни или загородного домика.

Блюдо из спичек

Безусловно это невероятно кропотливая работа, но ведь в итоге получился креативный и очень модный предмет интерьера.

Композиция из спичек

Такие поделки особенно понравится создавать детишкам. Ведь при помощи спичек можно построить самый настоящий дом.

 

Поделки из спичек

Из какой древесины делают спички?

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

Из древесины каких пород делаются обычные бытовые спички? Какие типы этого товара существуют? Каков процесс их производства? Об этом можно будет узнать ниже.

Породы деревьев, используемых в производстве спичек

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

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

Удовлетворяют таким требованиям не все породы деревьев.

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

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

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

Наиболее подходящей для производства спичек является осина.

Ее древесина легко обрабатывается, дает мало сколов, практически свободна от смоляных вкраплений. В тех местностях, где это дерево не растет, для получения спичек на заводах используется липа, береза. Можно употреблять для изготовления бытовых спичек тополь или ольху — они лишь немногим уступают по основным свойствам осине.

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

Какие виды спичек можно получить?

Разновидностей подобной продукции очень много. Они отличаются по цвету головки, составу, который позволяет получить пламя, различны по параметрам самого процесса горения.

Спичечные заводы производят много разных типов спичек, но наиболее популярны такие из них:

  1. Бытовые типы, предназначенные для курильщиков и домохозяек.
  2. Каминный вид — для зажигания огня в печах, каминах и т. д.
  3. Газовые спички — их основное назначение — поджигание газа на газовых плитах.
  4. Для пайки изобретены специальные термические образцы спичек.
  5. Охотничий тип такой продукции может гореть в непогоду, при ветре или дожде, а многие образцы способны дать пламя и под водой.
  6. Применяются специальные виды, называемые сигнальными спичками. Они могут гореть разноцветным пламенем.
  7. Для создания мощной вспышки при фотографии часто применяют специальный (фотографический) тип горючей продукции.

Чаще всего люди употребляют бытовые типы продукции спичечных заводов.

Вторыми по применяемости можно считать охотничьи спички. После появления цифровых фотокамер фотографические типы горючей продукции используются довольно редко.

Как делают спички на заводе?

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

Вот типичные этапы производства горючей продукции на спичечном заводе:

  1. Подготовительный процесс, который включает в себя очистку осины от коры и распиливание ее ствола на бруски.
    Древесина этой породы однородна по своей структуре, разрезается легко, прекрасно впитывает в себя наносимые на поверхность химические смеси.
  2. Затем делают ножки для спичек.
    Технологический процесс зависит от типа самой основы. Если изделие должно иметь квадратное сечение, то используется шпоновый способ. Для этого из брусков осины нарезают ленты, которые имеют ширину, равную длине будущей спички. Затем в специальном автомате лента режется на солому, которую потом разрезают на отдельные ножки.
    Если надо получить основу, которая должна в сечении быть кругом, то используют штамповку.
  3. После этого ножки отправляют в специальные ванны, где они пропитываются различными химическими составами.
    Вначале ножки погружают в противопожарную смесь, а затем они проходят обработку парафином.
  4. Наступает главный этап — на основу наносят головки, в которых находятся нужные ингредиенты, способные вызвать при трении о специальную поверхность горение.
  5. Затем почти готовые спички покрывают защитными слоями.
  6. Готовые спичечные палочки проходят сушку в предназначенной для этого машине.
  7. Затем их отправляют на полировальный участок, где спичкам придается товарный вид.
  8. На последнем этапе готовая продукция сортируется, отбраковывается, укладывается в коробочки.

Вместе с исходной древесиной осины для производства спичек употребляются такие химикаты, как парафин, бихроматы калия, медный купорос, и другие соединения.

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

Употребляется и автомат для нанесения фосфорной смеси, и станки для создания коробков и другой упаковки.

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

Смотрите также:
  • Тонкости в остеклении «хрущевских» балконов
  • Из чего делают фарфор?
  • Столешницы из жидкого камня
  • Каменная столешница для кухни
  • Уголок на кухню
  • Диван для кухни: какую модель выбрать
  • Поделки из спичек.

    Домик. Мастер-класс — Спички — Дерево — Каталог статей — УМЕЛЫЕ РУЧКИ

    Эта поделка самая интересная и захватывающая. Для изготовления поделки из спичек нужны только спички. Для того что-бы получился домик, не нужно ни клея, ни гвоздей. Все работы со спичками мы будем выполнять голыми руками. 

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

     

     

    Для изготовления домика из спичек на нужны спички (около 5-6 коробок), коробка от диска или другой плоский предмет и монета. Если у вас сохранились советские монеты, то подойдут 3 копейки. Если вы житель России, то можете использовать 2 рубля. 

    Положите коробку от диска или другой плоский предмет перед собой. Коробка будет служить столом, на котором будем собирать домик. Поставьте две спички перед собой параллельно друг другу. Расстояние между спичками должно быть немного меньше чем длинна одной спички. (Посмотрите на рисунке)

     

    На эти спички ложем 8 других спичек. Важно чтобы спички лежали ровно и между ними был пропуск как на рисунке. Края нижних двух спичек должны немного торчать! 

     

     

    По такому же принципу ставим еще 8 спичек. Их тоже нужно ставить перпендикулярно нижнему ряду. Расстояния между спичками желательно делать одинаковым, но это не обязательно. 

     

     

    Теперь внимательно посмотрите на рисунок. Нужно сделать стены. Для этого строим конструкцию напоминающую колодец. Нужно 7 рядов спичек выстроить вверх. Очень важно сделать стены ровными, иначе поделка может не получиться. Головки спичек в стене нужно ставить по часовой стрелке (по кругу), что-бы на одной стороне всегда была только один ряд спичек с головками. 

     

     

    На стены домика ложем 8 спичек как делали в начале. Головки спичек нужно ставить   противоположно нижнему. (Посмотрите на рисунке. В нижнем ряду не видно головок, а в верхнем — видно)  

     

     

    Параллельно этому ряду ставим новый настил из 6 спичек.  Крайние 2 спички мы добавим позже. На спички (в центре) нужно положить монету. Она будет поддерживать спички и не дать им развалиться.   

     

     

    Надавите на монету пальцем для большей устойчивости и вставьте по краям домика спичку как видно на рисунке. Головка спички должна быть вверху иначе домик развалится. Так нужно поставить по одной спичке в каждом углу домика. 

     

     

    Если спичка не проходит до конца из-за уже положенных спичек, нужно аккуратно их раздвинуть. Спички лучше раздвигать другой спичкой, так будет аккуратнее и проще. 

     

     

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

     

     

    Сожмите стены домика рукой и вытащите монету. Аккуратно сожмите все стороны для их укрепления. Теперь домик разваливаться не должен и его можно брать в руки. Вдавливаем спички, которые шли по периметру до конца так, что бы они прижимали головками настил. Головки спичек — это нижняя часть домика. Обратите внимание, что для продолжения работы, домик должен стоять на головках спичек.  Продолжение работы с домиком можно проводить в руках и подставка нам не нужна.  

     

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

     

     

    Теперь кладем горизонтальный слой стен. Спички должны идти по кругу, как при строительстве колодца и головки спичек должны чередоваться с концами спичек.

     

    Осталось сделать крышу. Вставляем недостающие спички в угловые дырки и вытаскиваем их немного вверх. Угловые спички должны немного выступать как на рисунке.  

     

    Кладем спички крыши перпендикулярно верхнему настилу. Начиная с краев и чередуя направления спичек, кладем сначала по 2, потом по 4, потом по 6 и в двух средних рядах — по 8 спичек. 

     

     

     

     

     

    Конструкцию домика можно усовершенствовать. Можно на крышу добавить еще один слой спичек. Аккуратно положите спички на крышу как на рисунке. Для закрепления спичек, надавите на них пальцем и пропихните между головками спичек крыши. Немного сложно, но внимательно посмотрите на рисунок.  

    Все, поделка из спичек готова. Можно еще немного украсить и сделать дымоход. Просто впихните 4 спички в крышу и дымоход готов. Можете таким же образом сделать окна и двери. 

    Берегите изделие от детей. Я в детстве таких штук десять сжег 🙂 Вот вам и домик из спичек!

    Как делают спички?


    Спички — самое доступное и распространенное приспособление для получения огня. Задумывались ли вы, как делают спички на заводе?

    Спичка — это узенькая деревянная палочка с темно коричневой или черной (реже цветной) головкой, которая производит огонь посредством трения головки о шероховатую поверхность, нанесенную, как правило, на боковую часть коробка.

    Первые спички были изобретены достаточно давно (1833 год), но современный вид и широкую популярность обрели относительно недавно. До этого спички проходили длинный процесс доработки и совершенствования, так как самые первые спички были попросту опасны для использования в домашних условиях — бывали случаи самовозгорания,  могли привести к возгоранию одежды человека во время использования.

     

    Рассмотрим подробнее процесс производства спички

    Из какой древесины производят спички?

    Самым «спичечным» деревом принято считать осину. Из нее производят большую часть спичек в мире. Осина имеет мягкую древесину, обладает однородной текстурой, легка в обработке. Горит такое дерево ровно, не создает копоти.  Осина быстро растет, абсолютно не требовательна к почве и хорошо переносит засухи и морозы, это делает ее экономически выгодной для производства спичек.

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

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

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

    Виды спичек

    Большинство людей даже не догадываются сколько видов спичек на самом деле существует.

    Виды спичек:

    — бытовые — это самые обычные спички в пятисантиметровом коробке знакомые каждому из нас;

    — штормовые — эти спички длиннее обычных и не имеют головки, они полностью пропитаны специальным составом, который придает им большую горючесть. Такие спички горят дольше обычных и могут гореть в любых условиях, даже при высокой влажности в шторм. Такой вид спичек особенно популярен среди моряков и рыбаков;

    — газовые — такие спички длиннее бытовых. Созданы для удобства и более безопасного поджигания газовой плиты;

    — каминные;

    — охотничьи — способны гореть при любом ветре;

    — спички для разкуривания сигар и трубок;

    — сигнальные — горят разными цветами.

    В нашей стране самыми популярными являются бытовые спички.

    Также все спички делят на две категории:

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

    не терочные — такие спички зажигаются от трения по любой поверхности. Популярны в Англии и Америке.

    Производство спичек

    Рассмотрим как спички делают на заводе:

    — первый этап производства спичек — заготовка древесины.

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

    Затем заготовленные стволы дерева нарезают на метровые колодки. Это делают для большего удобства обработки.

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

    — третий этап производства- это обработка древесных заготовок. Сначала их вымачивают в ваннах со специальным ортофосфорным  раствором, а потом обрабатывают парафином. Для чего это делают? Если бы не специальная обработка парафином, огонек на спичке гас бы сразу после того, как сгорит головка, то есть очень быстро, а парафин, которым смазана основа, легко воспламеняется и продлевает горение спички.

    — следующий этап — это нанесение головки. В состав смеси которая наносится на край деревянной соломки входят специальные химические компоненты смешанные с клеем и красителем.

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

    Подробнее этапы производства спичек смотрите в видеоролике. Приятного просмотра!

    Ирина Железняк, Собкор интернет-издания «AtmWood. Дерево-промышленный вестник»

    Насколько информация оказалась для Вас полезной?  Loading …

    Похожие статьи:

    Copyright © atmwood.com.ua. Копирование материала разрешено при указании гиперссылки на источник

    Из какого дерева делают спички? Разновидности спичек и процесс изготовления

    Спички можно найти в любом доме, даже там где еду готовят на электроплите. Этот предмет является мобильным источником огня, поэтому почти всегда лежит в кармане, не только у курильщиков, но и охотников, рыбаков, военных, да и у обычных домохозяек. И хотя они знакомы нам с детства, далеко не все знают, из какого дерева делают спички. Ведь не всякая древесина подходит для их изготовления. Попробуем разобраться в этом вопросе подробнее.

    Какое дерево подойдёт для изготовления спички?

    Слово спичка стало использоваться в обиходе человека относительно недавно. Еще в 18 веке, так величали гвоздь, выполненный из дерева, который применяли мастера обуви в ремонте. Позднее это название позаимствовала спица, которая помогала разжигать огонь, но ее не просто называли спичкой, а добавляли слово самогарная. В процессе изготовления очень тщательно подходили к вопросу выбора древесины. Ведь даже чтобы ножка получила идеально ровную форму, материал должен был быть идеального качества, хорошо просушенный.

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

    Подходящей считается следующая древесина:

    • Легкая.
    • С высокой прочностью.
    • Без смоляных вкраплений.
    • Низкой плотности.
    • Хорошо просушенная.

    При этом полотно не должно растрескиваться, чтобы его проще было обрабатывать. Перечисленным вариантам отвечают далеко не все породы. Например, хвойные деревья из-за сильной смолистости не используются в производстве вовсе. Дуб и красное дерево отлично подходит по критериям, однако если бы их задействовали в изготовлении, то коробок спичек мало кому был бы по карману. Ведь эти породы очень ценные и дорогие, чаще их используют при производстве мебели.

    Поэтому в качестве сырья чаще всего берут осину. Именно она легкая, и не раскалывается в процессе обработки. К тому же в ней практически отсутствуют смоляные вкрапления. Но из-за своей привередливости осиновые рощи встретить можно далеко не повсеместно. Поэтому в тех местностях, где она не растет, и привозить ее туда затратно, на заводах применяют:

    • Березу.
    • Липу.
    • Тополь.
    • Ольху.

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

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

    Разновидности спичек?

    Для многих знакомы только бытовые спички, но на самом деле разновидностей их бывает намного больше. Отличают их по внешнему виду и назначению, обычно они разные:

    • По цвету головки.
    • Составу вещества для возгорания.
    • Размеру.

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

    • Бытовые – для зажигания бытовых приборов, электропечей, котлов и прочего.
    • Для каминов – для розжига печей и каминов они имеют больший размер и более длинную ножку.
    • Газовые – специально приспособлены для использования при поджигании газа в плитах.
    • Для спаивания – имеют специально разработанную термическую структуру.
    • Охотничьи – отличительной особенностью является устойчивость к влаге, их можно легко поджечь даже в ветер и непогоду. Некоторые виды могут воспламеняться даже под водой.
    • Сигнальные – пламя имеет различный оттенок.

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

    Как проходит процесс производства спичек?

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

    Конструкция состоит из:

    • Головки с веществом, которое провоцирует образование огня при трении.
    • Основы (деревянной ножки).
    • Специальной поверхности с шероховатой структуры.

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

    На втором этапе заготавливают ножки. Весь процесс во многом будет зависеть от типа основы, так как очень важно, чтобы полученный результат был квадратной формы. Обычно на этом этапе задействуются специальные ленты, которые по ширине идентичны с будущей спичкой. Для изделий с круглой формой обычно задействуют штамповку.

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

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

    • Медный купорос.
    • Парафин.
    • Бихромат калия.

    Коробочки изготавливаются из обычного картона. Часто для этого задействуют вторсырье. Для более дорогой продукции используют плотную бумагу или пластинки дерева. На современном заводе нельзя увидеть дешевых станков, и почти весь процесс автоматизирован. В процессе задействуются режущие машинки, автоматы для спила под углом, массивные агрегаты для сушки, виброавтоматы, полировочные приборы и распылители для химического раствора. Все это помогает в процессе изготовления столь нужного для всех товара, как бытовые спички.

    Видео инструкция

    Поделки из спичек — варианты создания и инструкция по сборке различных поделок

    Спички – это очень удобный и не дорогой поделочный материал. Он может олицетворять любой полет фантазии. Из них можно делать картины, игрушки, архитектурные макеты и любые другие. Из спичек получаются очень красивые поделки. Их можно оформлять в рамы, колбы и другие футляры. Уникальные поделки из спичек могут дополнить интерьер вашего дома.

    Краткое содержимое статьи:

    Спички как искусство

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

    Инструменты для создания поделок найдутся в каждом доме. Фото с поделками из спичек впечатляют своим разнообразием и тонкостью изготовления. Существует работа, попавшая в книгу рекордов Гиннеса. Один британский чудак, выйдя на пенсию, решил построить из спичек мини копию нефтяной платформы размером в длину – 6,4 метра, а в высоту – 3,7 метра.

    Техника изготовления

    Существует два вида создания поделок из спичек: с использованием клея и без него.

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

    Из-за того, что работа с клеем легче, то она становиться под силу даже детям. Используя специальные технологии, можно добиться изогнутой конфигурации спички.

    Вид создания без клея. Он более сложен, так как требует определенных навыков работы со спичками по этому не стоит начинать работать сразу без клея. Но среди такого вида создания существуют и простые фигуры. Если вы овладеете базовыми элементами, то сможете делать и более сложные вещи. Еще мы хотим посоветовать вам сайт https://podelki.guru здесь вы найдете массу нестандартных решений по созданию поделок своими руками.


    Только работы выполненные без клея предоставляют возможность создать изящные фигуры и реализовать более сложные идеи.

    Варианты того, что можно сделать

    Для того, чтобы легко изготавливать поделки из спичек, для начала нужно пожелать этого, затем начинать с простых фигур и постепенно переходить к более сложным. Элементарной базовой стерео фигурой можно считать домик.

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

    Работать со спичками можно в комбинации с другими поделочными материалами: ткань, мешковина, бумага и многое другое.

    Пошаговая инструкция по созданию

    Люди не равнодушные к творчеству из спичек занимаются планированием и выпуском полуфабрикатов. Такие конструкции собираются по заранее прописанным инструкциям. Их можно найти в интернете, в печатных изданиях. Готовые конструкторы можно найти в магазинах детских игрушек. Они называются: “Поделки из спичек пошагово своими руками”. Нужно найти подходящее место, где будите конструировать. Постелить что-нибудь на место, где собираетесь работать.

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

    Польза от процесса

    Вам предоставляется возможность увлекательно и с пользой провести время. Из спичек получаются интересные головоломки. Что касаемо детей, у них данный процесс может развить ряд качеств, таких как: сообразительность, внимательность, эстетический вкус, аккуратность, целеустремленность, архитектурное мышление и конструкторские способности.

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

    Вниманию родителей! Работа со спичками требует контроля со стороны взрослого человека. Только убедившись, что ваш ребенок способен не причинить себе вред, например, засунуть в нос, ткнуть в глаз, попробовать разжечь, можете позволить ему заниматься самостоятельно.

    Некоторые родители пытаются выявить способности своих детей в раннем возрасте. Собирание фигурок из спичек один из способов обнаружить и развивать мелкую моторику, которая необходима в таких профессиях, как ювелир, стоматолог, хирург. Желаем вам постигнуть искусство спичечных технологий, воплотить их в жизнь и сделать мир прекраснее.

    Фото поделок из спичек


    Также рекомендуем просмотреть:

    Поделитесь с друзьями 😉  

    Из какого дерева делают спички 🚩 из какого сизаля делают деревья 🚩 Разное

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

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

    Спички из осины не дают копоти, горят ровным пламенем, очень легко воспламеняются. Там, где осина является редкостью, используют другие деревья со сходными свойствами, например, ольху, тополь, липу или березу. А вот сосна и ель для производства спичек не подходят: их смолистая древесина способна загореться при сушке исходного сырья, да и горят такие спички не совсем ровным пламенем.

    Материал для изготовления спичечной основы заготавливают, как правило, в зимнее время года. В этот период стволы деревьев имеют самую подходящую влажность. Деревья освобождают от сучьев, распиливают на чурбаны и доставляют на спичечную фабрику. Здесь заготовки тщательно сортируют, отбраковывая те экземпляры, которые не соответствуют требованиям стандартов.

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

    На следующей стадии осиновый шпон разрубают в поперечном и продольном направлении. В результате получается соломка – одинаковые тонкие палочки, которым предстоит стать основой для будущих спичек. Теперь заготовки пропитывают специальными составами, предотвращающими тление. После этой операции палочки загружают в барабан, где они шлифуются, взаимодействуя друг с другом.

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

    Как добавить совпадения ДНК в древо предков — Семейный медальон

    Использование программы генеалогического древа для организации совпадений ДНК полезно по нескольким причинам. Вы можете:

    — добавьте совпадения ДНК в свое дерево и свяжите их с вашим общим предком
    — включите совпадения ДНК из различных тестовых баз данных в одном центральном месте
    — проверьте доказательства для каждого родительско-дочернего отношения и добавьте документацию
    — создайте быстрые деревья для ДНК совпадения, у которых не было общего дерева
    — проведите исследование потомков, чтобы найти потенциальных участников теста
    — построить дерево совпадений, проверяя наличие более чем одного общего предка

    Многие из ваших совпадений ДНК могут иметь небольшие деревья, которые не уходят достаточно далеко, чтобы найти общего предка.Специалисты по генетической генеалогии часто используют инструменты построения деревьев, такие как Ancestry.com, для быстрого создания деревьев для сопоставления ДНК. В Ancestry есть полезные инструменты для построения деревьев, такие как подсказки, которые помогают быстро строить деревья. Однако создание нового дерева для каждого совпадения ДНК быстро пополняет ваш список деревьев предков. Если вы не хотите иметь длинный список деревьев предков, создайте одно главное генетическое дерево и включите все совпадения ДНК тестируемого или определенной стороны семьи.

    Настройки конфиденциальности для деревьев предков

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

    Общедоступные деревья доступны для просмотра тем, кого вы пригласили для совместной работы, и всем, у кого есть подписка Ancestry. Люди в вашем дереве, отмеченные как живущие, автоматически приватизируются для тех, кто не приглашен к совместной работе над вашим деревом.

    Частные и доступные для поиска деревья отображаются в результатах поиска в базе данных общедоступного дерева элементов, но для просмотра дерева пользователи должны сначала запросить ваше разрешение.Для работы Ancestry Thrulines ваше дерево должно быть публичным или приватным / доступным для поиска.

    Частные и недоступные для поиска деревья не отображаются в результатах поиска и не используются в Ancestry Thrulines. Вы можете пометить свои деревья исследований как недоступные для исследования, чтобы другие не копировали недоказанные взаимосвязи в свои деревья. Для этого перейдите в настройки дерева> настройки конфиденциальности. Оттуда выберите «Частное дерево», а затем установите флажок ниже, в котором говорится «также предотвратить обнаружение вашего дерева при поиске».”

    Если вы хотите, чтобы ваши частные деревья, недоступные для поиска, никто не мог найти, не сохраняйте изображения, которые другие пользователи Ancestry добавили в ваше дерево. Сюда входят изображения профиля предков, изображения надгробий и т. Д. Эти изображения часто добавляются, когда вы быстро строите дерево для сопоставления ДНК и используете подсказки по деревьям членов предков. Каждый раз, когда кто-то сохраняет эти фотографии в свое дерево, его имя пользователя и имя дерева добавляются в список «в других генеалогических деревьях» на боковой панели страницы с информацией о фотографии в Ancestry.Чтобы удалить фотографии, добавленные в ваше личное дерево, перейдите в «медиа-галерею» и щелкните фотографию, чтобы удалить ее из своего дерева. Если вы работаете с деликатным делом, вы можете сохранить свое дерево на таком высоком уровне конфиденциальности.

    Добавление совпадений ДНК к вашему дереву

    Добавьте свои совпадения ДНК как потомков предков, которых вы уже определили в своем дереве, построив родословную до наших дней. Обязательно отметьте свои совпадения ДНК как живых, а также как их родителей, если вы не знаете, что они умерли.Любой, кто отмечен как живущий, будет закрыт, когда другие будут просматривать ваше дерево, если вы не добавили этого зрителя в качестве соавтора.

    Обычно я добавляю к своему дереву совпадения ДНК, которые, как мне кажется, могут быть полезны при доказательстве определенного случая. Затем я прикрепляю источники для документирования каждого родительско-дочернего отношения к общему предку. Когда пришло время написать доказательство, я могу процитировать это дерево, которое я создал, или добавить цитаты для каждой родительско-дочерней ссылки непосредственно в свой доказательный аргумент.

    После добавления профиля генетического кузена к вашему дереву вы можете связать его страницу совпадения ДНК с этим профилем.Для этого перейдите на страницу совпадения ДНК генетического кузена и найдите значок родословной. Щелкните значок, чтобы найти их в дереве и связать их. После этого на генетическом родственнике в вашем дереве появится значок, указывающий, что они совпадают по ДНК. В дереве вы можете щелкнуть значок, чтобы перейти на страницу соответствия. Вы также можете щелкнуть значок в своем списке совпадений ДНК, чтобы перейти к их профилю в вашем дереве, как показано ниже.

    Добавление совпадений в древо предков — полезный способ визуализировать совпадения ДНК в генеалогическом древе, особенно при просмотре его в режиме просмотра «Семья / потомство».

    Добавление людей к вашему дереву с помощью Thrulines предков

    Thrulines предков показывают, как вы можете быть связаны с совпадениями ДНК через общего предка. Если у вас есть общедоступное или частное дерево с возможностью поиска, связанное с вашими результатами ДНК, вы получите Thrulines. Thrulines — это не подтвержденные выводы о предках, а предположения, которые могут привести вас к заключению. Ancestry использует общедоступные и частные деревья с возможностью поиска в своей базе данных, чтобы генерировать предложения Thrulines для вас и совпадений вашей ДНК.Thrulines не оценивает количество общей ДНК между вами и вашим партнером, прежде чем предложить конкретного общего предка.

    Thrulines упрощает добавление совпадений ДНК в ваше генеалогическое древо. Хотя вы не можете добавлять сами совпадения в Thrulines, вы можете их происхождение от предполагаемого общего предка. Дерево, прикрепленное к результатам вашей ДНК, — это дерево, которое будет обновляться, когда вы добавите людей из Thrulines.

    Если в Thrulines есть пунктирная линия вокруг человека с пометкой «оценить», это означает, что его нет в вашем дереве.Например, вы можете найти родного брата вашего предка, которого вы еще не добавили в свое дерево, как , показанное ниже . У этого нового брата вашего предка есть несколько потомков, которые совпадают с вами по ДНК.

    Чтобы добавить этого нового брата и совпадения ДНК в ваше дерево, щелкните поле брата, чтобы открыть боковую панель и просмотреть прикрепленные источники. Если все в порядке, нажмите «Далее» и добавьте их в свое дерево. Продолжайте добавлять потомков брата или сестры, пока не дойдете до совпадения ДНК.Затем вам придется вручную добавить совпадение ДНК в свое дерево. После добавления родителя совпадения ДНК нажмите кнопку на боковой панели, чтобы просмотреть профиль родителя. На странице их профиля вы можете добавить совпадение в свое дерево, нажав «добавить ребенка». В Thrulines вы можете щелкнуть поле с людьми в своем дереве, чтобы попасть прямо на страницу их профиля.

    Если вы видите предложение Thrulines со всеми совпадениями ДНК, происходящими только от одного ребенка, это может быть неточным. Найдите предка, у которого есть потомки от нескольких детей, ДНК которых совпадает с вами.

    Добавление отключенной ветви

    Добавление совпадения ДНК в качестве отдельной ветви в ваше дерево позволяет вам строить его дерево, пока вы не обнаружите общего предка. Как только вы найдете соединение, вы можете связать их плавающую ветку с предком, который уже был в дереве. Построение деревьев для совпадений с общим размером менее 15 см может быть бесполезным, поскольку они могут быть ложными совпадениями или могут не иметь общего предка с вами в генеалогическом временном интервале. [1] По возможности работайте над построением деревьев более близких совпадений.

    Чтобы добавить человека в свое семейное древо, когда вы не знаете, как он связан с кем-либо, уже включенным в дерево, вы должны сначала добавить его в качестве супруга или ребенка, а затем удалить связь. После этого они будут «плавающей» или отключенной ветвью в дереве. Как только родство определено, человека можно связать с известными предками в дереве и восстановить связь.

    Обычная причина для добавления плавающей ветви — это когда вы строите дерево для близкого совпадения ДНК (вероятно, более 40 см), которое, как вы уверены, связано в генеалогических временных рамках.Есть надежда, что после расширения их родовых линий вы найдете общего предка и сможете связать их со своим существующим деревом. В этом случае вы добавите имя своего совпадения ДНК в виде плавающей ветки к своему дереву, а затем поработаете, чтобы построить его дерево. Вы можете использовать функцию My Tree Tags, чтобы пометить свои совпадения, чтобы вы могли найти эти плавающие ветви позже. Мне нравится добавлять ссылку на их позицию в моем дереве в журнал исследования, чтобы помнить, что я работал над этим деревом соответствий.

    Самый простой способ добавить плавающую ветку к дереву предков — добавить их в качестве супругов к существующему человеку, а затем удалить отношения.Это даже проще, чем добавлять их в детстве, потому что у вас есть только один человек, с которым нужно разорвать отношения. Перейдите к профилю любого человека в вашем дереве и нажмите кнопку «+ добавить» справа рядом с «Семья», затем нажмите «супруг». Во всплывающем окне введите имя генетического совпадения или человека, которого вы добавляете в качестве плавающей ветви. Выберите пол человека — если вы добавляете супруга к мужчине, пол будет автоматически выбран как женский, но вы можете его изменить.

    Если вы добавляете живого человека, например, генетического совпадения, обязательно выберите «живой», чтобы он оставался закрытым для людей, просматривающих ваше дерево. Нажмите «Сохранить». Прокрутите вниз, чтобы увидеть человека, которого вы добавили в список супругов. Нажмите на человека, чтобы перейти на страницу его профиля. Вверху страницы нажмите на значок карандаша с надписью «редактировать». В появившемся меню нажмите «изменить отношения». Во всплывающем окне для редактирования отношений вы увидите имя их «супруга». Щелкните X справа от их имени, чтобы удалить эту связь, и нажмите «удалить», когда система спросит, уверены ли вы, что хотите удалить эту связь.

    После того, как вы нажмете «Удалить», у добавленного вами человека не будет никаких связей, отображаемых в поле редактирования отношений. Вы можете щелкнуть x, чтобы закрыть это поле и начать построение своего дерева.

    Метка ДНК совпадает с MyTreeTags

    После добавления совпадения ДНК к вашему дереву рассмотрите возможность добавления тега «совпадение ДНК», который поможет вам сортировать и фильтровать совпадения в вашем дереве. Ancestry создала MyTreeTags, чтобы пользователи могли помечать людей в вашем дереве и фильтровать ваши поисковые запросы в дереве для людей с этим тегом.

    Ancestry имеет три тега ДНК по умолчанию, которые вы можете использовать для идентификации людей в вашем дереве. Они определены следующим образом:

    1. Общий ДНК-предок: общий предок между вами и хотя бы одним из ваших совпадений.
    2. Связь ДНК: Этот человек является родственником на пути между совпадением ДНК и общим предком.
    3. Соответствие ДНК: этот человек внесен в ваш список совпадений ДНК.

    MyTreeTags также позволяет создавать собственные теги. Пользовательские теги могут включать генетическую сеть, к которой принадлежат совпадения (т.е. по материнской линии, Дедушка Джонс, Росс / Сильвиус) или что-нибудь, что может быть вам полезно. Если вам нужно выполнить поиск в своем генеалогическом древе, вы можете использовать эти теги, чтобы быстро найти людей с определенным тегом.

    Исследуй как профессионал с книгой ДНК

    Чтобы узнать больше об использовании данных ДНК в ваших генеалогических исследованиях, обязательно получите нашу новую книгу (скоро выйдет) — Research Like a Pro with DNA: A Genealogist’s Guide. RLP с ДНК состоит из двенадцати глав об использовании результатов аутосомной ДНК для проверки документальных генеалогических исследований и выявления неизвестных предков.Мы также обсуждаем Y-ДНК и митохондриальную ДНК. Основное внимание в книге уделяется процессу, который мы используем в нашей профессиональной работе для организации совпадений ДНК, составления плана исследования, включающего документальные источники и источники ДНК, использования инструментов ДНК, отслеживания информации в журнале исследований и написания выводов. Подпишитесь на нашу рассылку, чтобы одним из первых получать уведомления о публикации электронной книги. Печатная книга будет опубликована вскоре после электронной книги.

    Банкноты

    [1] «Идентичны по происхождению», Международное общество генетической генеалогии, Wiki (https: // isogg.org / wiki / Identical_by_descent: последний раз редактировалось 6 ноября 2020 года в 13:08.)

    Нравится:

    Нравится Загрузка …

    Связанные

    python — алгоритм сопоставления деревьев?

    Я работаю над древовидной библиотекой, и часть необходимой функциональности — это возможность искать в узле дочерние узлы, соответствующие шаблону.

    «Шаблон» — это спецификация (или критерии), которые определяют структуру, а также атрибуты узлов в поддереве (ах), которые должны быть сопоставлены.

    Например, предположим, что дерево представляет данные о конкретном виде птиц. Далее предположим, что узлы такого дерева имеют следующие атрибуты:

    • расположение
    • секс
    • размах крыльев
    • вес
    • brood_size

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

    «Приведите мне всех самцов птиц, которые потомки этой птицы и живут в Город XXX и вес> 100 г.У любой такой найденной птицы также должно быть как минимум 2 брата и одна сестра, а также должен быть как минимум один ребенок «

    <примечание>

    Чтобы прояснить, я не ожидаю, что у меня будет возможность запрашивать, используя простой английский язык, как я сделал выше. Я использовал только «простой английский запрос», чтобы проиллюстрировать тип сопоставления, который я хотел бы выполнить на дереве. Я полностью ожидаю использования символов для сопоставления (в отличие от обычного текста) на практике.

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

    Кто-нибудь знает алгоритм, который позволит мне выбирать узлы (поддеревья) в узле на основе шаблона?

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

    комбинированных совпадений ДНК + совпадений деревьев на MyHeritage

    В обзорной статье 2018 года, которую я написал пару дней назад, один из читателей заметил, что они не осознавали, что MyHeritage объединила сопоставление ДНК с сопоставлением деревьев.

    Есть, и это очень просто.

    Сопоставление ДНК и дерева за 4 простых шага

    Вот как просмотреть свои комбинированные совпадения за 4 простых шага.

    1. Войдите в систему и нажмите «совпадения ДНК».

    1. Щелкните маленький значок фильтра.

    1. Щелкните «Все сведения о дереве».

    1. Затем нажмите «Имеет интеллектуальные совпадения».

    Вот и все!

    совпадений ДНК плюс совпадений SmartMatches

    Вуаля — при использовании этого параметра фильтра единственные совпадения, которые вы увидите, — это совпадения вашей ДНК, которые также являются SmartMatches, то есть у другого человека есть общий предок (или более) в дереве с вами.Вы увидите сочетание обеих функций. В качестве примера мы возьмем мой матч с Майклом.

    Прокрутите вниз, чтобы просмотреть всю вашу общую информацию об этом матче, в том числе:

    • Сводная информация (предполагаемая взаимосвязь,% совпадения, общее совпадение cM, количество общих сегментов, наибольший сегмент в cM,)

    • Общие фамилии предков

    • Совместные ДНК-совпадения, включая триангуляцию, обозначенную значком сегмента в фиолетовом кружке справа

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

    • Браузер хромосом — общие сегменты ДНК

    С кем вы сопоставляете, разделяете предков и триангулируете?

    Тестирование или перенос в MyHeritage

    Вы можете протестировать на MyHeritage или передать файл ДНК от других поставщиков в MyHeritage.

    Чтобы заказать тест ДНК, нажмите здесь.

    Чтобы передать файл ДНК в MyHeritage, щелкните здесь.

    В статье MyHeritage Step by Step Guide: How to Upload-Download Files вы найдете простые инструкции.

    Развлекайтесь😊

    ______________________________________________________________

    Раскрытие информации

    Я получаю небольшой взнос, когда вы нажимаете на некоторые (но не на все) ссылки на поставщиков в моих статьях. Это НЕ увеличивает цену, которую вы платите, но помогает мне держать свет включенным, и этот информационный блог бесплатный для всех.Пожалуйста, нажмите на ссылки в статьях или на поставщиков ниже, если вы покупаете продукты или проводите тестирование ДНК.

    Большое спасибо.

    Покупки ДНК и бесплатные переводы

    Услуги генеалогии

    Генеалогические исследования

    Как это:

    Нравится Загрузка …

    6 вещей, которые нужно делать, если у вашего совпадения ДНК нет дерева

    Q: Что мне делать с моими совпадениями ДНК, результаты которых не связаны с генеалогическими деревьями? Эти матчи бесполезны?

    A : У ДНК-тестеров может не быть онлайн-деревьев по многим причинам: их в первую очередь интересуют результаты по этнической принадлежности.Они усыновлены и ищут родные семьи. Они новички в семейной истории, и у них нет дерева. Они прошли тест на Рождество и не очень заинтересованы в результатах. Они потеряли работу или заболели.

    Никто не обязан предоставлять ДНК-совпадения с общедоступным деревом, но без него может быть сложно провести генетическую генеалогию. Но эти совпадения без дерева или с частным деревом далеки от от бесполезности.

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

    1. Найдите несвязанное дерево.

    Возможно, тестируемый AncestryDNA или MyHeritage DNA, у которого есть генеалогическое древо на сайте, просто не предпринял этого дополнительного шага, чтобы связать дерево со своим тестом.

    При просмотре списка совпадений в Ancestry вы можете увидеть обозначение несвязанного дерева. Нажмите, чтобы просмотреть совпадение, и вы увидите, какие общедоступные генеалогические деревья есть у этого пользователя. Просто помните, что это дерево может быть не для семьи вашего спички — например, это может быть дерево, которым спичка управляет для своей супруги.

    2. Выполните триангуляцию с общими совпадениями.

    Используйте инструмент «Общие совпадения» (называемый инструментом «Общие с» в Family Tree DNA), чтобы увидеть других участников теста, которые соответствуют как вам, так и совпадению без дерева. Есть ли у каких-либо из этих спичек деревья с фамилиями и местами, общими для вашей семьи? Триангуляция ДНК может помочь вам использовать известную информацию об одном совпадении, чтобы узнать о неизвестном совпадении.

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

    3. Используйте идентификатор пользователя.

    Ищите подсказки в идентификаторе пользователя. Например, ваше совпадение с идентификатором пользователя dbmartin23 может быть связано с ветвью Мартина в вашем генеалогическом дереве. Некоторые из них более тонкие, например, 14HorseBoy, который на самом деле соответствует семейству Colt. Помимо идентификатора пользователя, вы можете увидеть имя администратора.На Ancestry.com вы также можете искать имя пользователя в каталоге участников сайта.

    4. Посмотрим, есть ли администратор.

    Администратор теста — это тот, кто управляет учетной записью ДНК другого человека, прошедшего тест. Учетные записи с одним и тем же администратором обычно имеют какие-то общие отношения. Один администратор может проверять не только себя, но и родителей, и брата. Так что, если в одном из этих аккаунтов есть информация о родословной, она может быть полезна в вашем расследовании.

    5. Погуглите человека.

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

    6. Спросите.

    Если совпадение без дерева является близким родственником или может быть ключом к вашему исследованию, возможно, стоит написать, чтобы спросить, может ли человек поделиться некоторыми из своих фамилий или у него есть онлайн-дерево, где вы можете посмотреть.(Однако вы, вероятно, не захотите отправлять запросы всем 1022 вашим кузенам от пятого до восьмого). Если у человека есть личное дерево, связанное с его результатами теста, вежливо спросите, может ли он отправить вам приглашение просмотреть его.

    Пройдя вышеуказанные шаги, чтобы сформулировать предположение о взаимоотношениях, вы сможете лучше составить первоначальное контактное электронное письмо. Вместо «Дорогой Матч, поделитесь, пожалуйста, своей родословной», вы можете написать: «Можете ли вы сказать мне, какое у вас родство с Генри Кольтом, родившимся в 1872 году в Вирджинии? Моя бабушка — Элиза Кольт, дочь сына Генри Чарльза.”

    Добавьте дерево к

    Вашим результатам ДНК

    Теперь давайте рассмотрим, как добавить свою собственную генеалогию к результатам теста ДНК, чтобы не вы были тем человеком, у которого виртуальный кулак машут:

    • ДНК семейного дерева: войдите в систему и используйте кнопку myFamilyTree на домашней странице, чтобы загрузить файл GEDCOM. (GEDCOM — это тип файла, который содержит данные вашего генеалогического дерева. Вы можете экспортировать GEDCOM из своего генеалогического программного обеспечения или своего онлайн-дерева.)
    • MyHeritage DNA и AncestryDNA: просто свяжите свою учетную запись ДНК-теста с вашим онлайн-деревом на сайте.
    • 23andMe: Заполните свой профиль ограниченной семейной информацией, включая ссылку на онлайн-дерево, если оно у вас есть. Даже если вы не хотите публиковать в Интернете все свое генеалогическое древо, подумайте о том, чтобы связать результаты с «каркасным» деревом, содержащим только имена, даты рождения и места рождения только предков (родителей, бабушек и дедушек, прабабушек и дедушек и т. Д.).

    Версия этой статьи появилась в сентябрьском выпуске журнала Family Tree Magazine за 2017 год.

    Ответьте на свои вопросы о ДНК с помощью электронной книги «Решение проблем с ДНК»!

    Эта электронная книга не только поможет вам в выборе теста, но также поможет вам точно проанализировать данные ДНК и решить самые сложные проблемы с ДНК.С советами отраслевых экспертов вы найдете решения самых сложных проблем ДНК.
    КУПИТЬ

    деревьев в реальном мире

    Это шестой пост в серии.

    В предыдущем посте мы кратко рассмотрели некоторые общие типы.

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

    Вот содержание этой серии:

    • Часть 1: Введение в рекурсивные типы и катаморфизмы
    • Часть 2: Примеры катаморфизма
    • Часть 3: Введение в складки
    • Часть 4: Что такое складки
    • Часть 5: Универсальные рекурсивные типы
    • Часть 6: Деревья в реальном мире

    Определение универсального типа дерева

    В этом посте мы будем работать с общим Tree , вдохновленным доменом FileSystem , который мы исследовали ранее.

    Вот оригинальный дизайн:

      тип FileSystemItem =
        | Файл FileInfo
        | Справочник DirectoryInfo
    и FileInfo = {имя: строка; fileSize: int}
    и DirectoryInfo = {имя: строка; dirSize: int; subitems: список FileSystemItem}
      

    Мы можем отделить данные от рекурсии и создать общий тип Tree следующим образом:

      дерево типа <'LeafData,' INodeData> =
        | LeafNode из LeafData
        | InternalNode из 'INodeData * Tree <' LeafData, 'INodeData> seq
      

    Обратите внимание, что я использовал seq для представления подэлементов, а не list .Причина этого станет очевидной в ближайшее время.

    Затем можно смоделировать домен файловой системы с использованием Tree , указав FileInfo как данные, связанные с листовым узлом, и DirectoryInfo как данные, связанные с внутренним узлом:

      тип FileInfo = {имя: строка; fileSize: int}
    введите DirectoryInfo = {имя: строка; dirSize: int}
    
    введите FileSystemItem = Tree 
      

    Мы можем определить cata и сложить обычным способом:

      модуль Дерево =
    
        let rec cata fLeaf fNode (tree: Tree <'LeafData,' INodeData>): 'r =
            let recurse = cata fLeaf fNode
            дерево спичек с
            | LeafNode leafInfo ->
                fLeaf leafInfo
            | InternalNode (nodeInfo, поддеревья) ->
                fNode nodeInfo (поддеревья |> Seq.рекурс карты)
    
        let rec свернуть fLeaf fNode acc (tree: Tree <'LeafData,' INodeData>): 'r =
            let recurse = свернуть fLeaf fNode
            дерево спичек с
            | LeafNode leafInfo ->
                fLeaf acc leafInfo
            | InternalNode (nodeInfo, поддеревья) ->
                // определяем локальный аккумулятор на этом уровне
                let localAccum = fNode acc nodeInfo
                // пропустите локальный аккумулятор через все подэлементы, используя Seq.fold
                пусть finalAccum = поддеревья |> Seq.свернуть рекурсию localAccum
                // ... и вернуть его
                finalAccum
      

    Обратите внимание, что я не собираюсь реализовать foldBack для типа Tree , потому что маловероятно, что дерево станет настолько глубоким, что вызовет переполнение стека. Функции, которым нужны внутренние данные, могут использовать cata .

    Моделирование домена файловой системы с помощью дерева

    Давайте проверим его с теми же значениями, которые мы использовали раньше:

      пусть fromFile (fileInfo: FileInfo) =
        LeafNode fileInfo
    
    пусть fromDir (dirInfo: DirectoryInfo) subitems =
        InternalNode (dirInfo, подэлементы)
    
    пусть readme = fromFile {name = "readme.txt "; fileSize = 1}
    пусть config = fromFile {name = "config.xml"; fileSize = 2}
    пусть build = fromFile {name = "build.bat"; fileSize = 3}
    пусть src = fromDir {name = "src"; dirSize = 10} [readme; config; строить]
    пусть bin = fromDir {name = "bin"; dirSize = 10} []
    пусть корень = fromDir {имя = "корень"; dirSize = 5} [src; bin]
      

    Функция totalSize практически идентична той, что была в предыдущем посте:

      пусть totalSize fileSystemItem =
        пусть fFile acc (файл: FileInfo) =
            acc + файл.размер файла
        пусть fDir acc (dir: DirectoryInfo) =
            acc + dir.dirSize
        Tree.fold fFile fDir 0 fileSystemItem
    
    readme |> totalSize // 1
    src |> totalSize // 16 = 10 + (1 + 2 + 3)
    корень |> totalSize // 31 = 5 + 16 + 10
      

    И так же функция largeFile :

      пусть самый большой файл fileSystemItem =
        пусть fFile (самый большойSoFarOpt: параметр FileInfo) (файл: FileInfo) =
            сопоставить largeSoFarOpt с
            | Нет ->
                Какой-то файл
            | Некоторые самые большиеSoFar ->
                если самый большойSoFar.fileSize> file.fileSize, затем
                    Некоторые крупнейшие
                еще
                    Какой-то файл
    
        пусть fDir наибольшийSoFarOpt dirInfo =
            самый большойSoFarOpt
    
        // вызываем свертку
        Tree.fold fFile fDir Нет fileSystemItem
    
    readme |> самый большой файл
    // Немного {name = "readme.txt"; fileSize = 1}
    
    src |> самый большой файл
    // Немного {name = "build.bat"; fileSize = 3}
    
    bin |> самый большой файл
    // Никто
    
    корень |> самый большой файл
    // Немного {name = "build.bat"; fileSize = 3}
      

    Исходный код этого раздела доступен по этой сути.

    Тип дерева в реальном мире

    Мы также можем использовать дерево для моделирования реальной файловой системы ! Сделать это, просто установите тип конечного узла на System.IO.FileInfo и тип внутреннего узла на System.IO.DirectoryInfo .

      открытая система
    откройте System.IO
    
    тип FileSystemTree = Tree 
      

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

      пусть fromFile (fileInfo: FileInfo) =
        LeafNode fileInfo
    
    пусть rec fromDir (dirInfo: DirectoryInfo) =
        let subItems = seq {
            урожай! dirInfo.EnumerateFiles () |> Seq.map fromFile
            урожай! dirInfo.EnumerateDirectories () |> Seq.map fromDir
            }
        InternalNode (dirInfo, подэлементы)
      

    Теперь вы можете понять, почему я использовал seq , а не list для подэлементов. seq ленивый, что означает, что мы можем создавать узлы. фактически не ударяя по диску.

    Вот снова функция totalSize , на этот раз с использованием реальной информации о файле:

      пусть totalSize fileSystemItem =
        пусть fFile acc (файл: FileInfo) =
            acc + файл.Длина
        пусть fDir acc (dir: DirectoryInfo) =
            соотв
        Tree.fold fFile fDir 0L fileSystemItem
      

    Давайте посмотрим, каков размер текущего каталога:

      // установить текущий каталог в текущий исходный каталог
    Directory.SetCurrentDirectory __SOURCE_DIRECTORY__
    
    // получаем текущий каталог как дерево
    пусть currentDir = fromDir (DirectoryInfo ("."))
    
    // получаем размер текущего каталога
    currentDir |> totalSize
      

    Аналогично получаем самый большой файл:

      пусть самый большой файл fileSystemItem =
        пусть fFile (самый большойSoFarOpt: параметр FileInfo) (файл: FileInfo) =
            сопоставить largeSoFarOpt с
            | Нет ->
                Какой-то файл
            | Некоторые самые большиеSoFar ->
                если самый большойSoFar.Длина> файл. Длина тогда
                    Некоторые крупнейшие
                еще
                    Какой-то файл
    
        пусть fDir наибольшийSoFarOpt dirInfo =
            самый большойSoFarOpt
    
        // вызываем свертку
        Tree.fold fFile fDir Нет fileSystemItem
    
    currentDir |> самый большой файл
      

    Итак, это одно большое преимущество использования общих рекурсивных типов. Если мы сможем превратить реальную иерархию в нашу древовидную структуру, мы сможем получить все преимущества сворачивания «бесплатно».

    Сопоставление с универсальными типами

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

    Мы можем увидеть это в действии с реальной файловой системой. Но сначала нам нужно определить карту для типа Tree !

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

    • Создайте параметр функции для обработки каждого случая в структуре.
    • Для нерекурсивных случаев
      • Сначала используйте параметр функции для преобразования нерекурсивных данных, связанных с этим случаем
      • Затем оберните результат в тот же конструктор case
    • Для рекурсивных случаев выполните два шага:
      • Сначала используйте параметр функции для преобразования нерекурсивных данных, связанных с этим случаем
      • Затем рекурсивно сопоставьте вложенных значений.
      • Наконец, оберните результаты в тот же конструктор case

    Вот реализация карты для дерева , созданная в соответствии с этими правилами:

      модуль Дерево =
    
        пусть rec cata ...
    
        пусть rec фолд ...
    
        пусть rec map fLeaf fNode (tree: Tree <'LeafData,' INodeData>) =
            let recurse = map fLeaf fNode
            дерево спичек с
            | LeafNode leafInfo ->
                пусть newLeafInfo = fLeaf leafInfo
                LeafNode newLeafInfo
            | InternalNode (nodeInfo, поддеревья) ->
                пусть newNodeInfo = fNode nodeInfo
                пусть newSubtrees = subtrees |> Seq.рекурсивная карта
                Внутренний узел (newNodeInfo, newSubtrees)
      

    Если мы посмотрим на подпись Tree.map , мы увидим, что все данные листа преобразуются в тип 'a , все данные узла преобразуются в тип ' b , и конечный результат — дерево <'a,' b> .

      val карта:
      fLeaf :( 'LeafData ->' a) ->
      fNode :( 'INodeData ->' b) ->
      дерево: Дерево <'LeafData,' INodeData> ->
      Дерево <'a,' b>
      

    Мы можем определить дерево .iter аналогично:

      модуль Дерево =
    
        пусть rec map ...
    
        позвольте получить fLeaf fNode (tree: Tree <'LeafData,' INodeData>) =
            let recurse = iter fLeaf fNode
            дерево спичек с
            | LeafNode leafInfo ->
                fLeaf leafInfo
            | InternalNode (nodeInfo, поддеревья) ->
                поддеревья |> Seq.iter recurse
                fNode nodeInfo
      

    Пример: создание списка каталогов

    Допустим, мы хотим использовать карту для преобразования файловой системы в список каталогов — дерево строк, где каждая строка содержит информацию о соответствующем файле или каталоге.Вот как мы могли это сделать:

      let dirListing fileSystemItem =
        пусть printDate (d: DateTime) = d.ToString ()
        пусть mapFile (fi: FileInfo) =
            sprintf "% 10i% s% -s" fi.Length (printDate fi.LastWriteTime) fi.Name
        пусть mapDir (di: DirectoryInfo) =
            di.FullName
        Tree.map mapFile mapDir fileSystemItem
      

    И затем мы можем распечатать строки следующим образом:

      currentDir
    |> dirListing
    |> Tree.iter (printfn "% s") (printfn "\ n% s")
      

    Результат будет примерно таким:

      8315 10/08/2015 23:37:41 Сложить.fsx
      3680 11.08.2015 23:59:01 FoldAndRecursiveTypes.fsproj
      1010 08.11.2015 01:19:07 FoldAndRecursiveTypes.sln
      1107 08.11.2015 23:59:01 HtmlDom.fsx
        79 08.11.2015 01:21:54 LinkedList.fsx
      

    Исходный код этого примера доступен по этой сути.


    Пример: создание параллельного grep

    Давайте посмотрим на более сложный пример. Я продемонстрирую, как создать параллельный поиск в стиле «grep», используя кратное .

    Логика будет такая:

    • Используйте сгиб для перебора файлов.
    • Для каждого файла, если его имя не соответствует желаемому шаблону файла, вернуть Нет .
    • Если файл должен быть обработан, вернуть асинхронный режим, который возвращает все совпадения строк в файле.
    • Затем все эти асинхронные операции — вывод свертки — объединяются в последовательность.
    • Последовательность асинхронных операций преобразуется в единую с помощью Async.Параллельный , который возвращает список результатов.

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

    Во-первых, общая функция, которая асинхронно переносит строки в файле. Это будет основой сопоставления с образцом.

      /// Асинхронное сгибание строк в файле
    /// передача текущей строки и номера строки в функцию папки.
    ///
    /// Подпись:
    /// папка :( 'a -> int -> строка ->' a) ->
    /// согласно: 'a ->
    /// fi: FileInfo ->
    /// Асинхронный <'a>
    пусть папка foldLinesAsync acc (fi: FileInfo) =
        async {
            пусть изменчивый acc = acc
            let изменяемая строкаNo = 1
            используйте sr = new StreamReader (path = fi.ФИО)
            пока не sr.EndOfStream делать
                позволять! lineText = sr.ReadLineAsync () |> Async.AwaitTask
                acc <- папка acc lineNo lineText
                lineNo <- lineNo + 1
            возврат в соотв.
        }
      

    Затем небольшой помощник, который позволяет нам сопоставить с асинхронными значениями :

      let asyncMap f asyncX = async {
        позволять! x = asyncX
        return (f x)}
      

    Теперь о центральной логике. Мы создадим функцию, которая, учитывая textPattern и FileInfo , будет возвращать список строк, которые соответствуют textPattern, но асинхронно:

      /// возвращаем совпадающие строки в файле как асинхронный <список строк>
    пусть matchPattern textPattern (fi: FileInfo) =
        // настраиваем регулярное выражение
        пусть регулярное выражение = текст.RegularExpressions.Regex (шаблон = textPattern)
    
        // настраиваем функцию для использования с "складкой"
        пусть папка результаты lineNo lineText =
            если regex.IsMatch lineText, то
                let result = sprintf "% 40s:% - 5i% s" fi.Name lineNo lineText
                результат :: результаты
            еще
                // пройти через
                полученные результаты
    
        // основной поток
        фи
        |> Папка foldLinesAsync []
        // вывод сгиба в обратном порядке, поэтому переверните его
        |> asyncMap List.rev
      

    А теперь для самой функции grep :

      разрешить grep filePattern textPattern fileSystemItem =
        пусть регулярное выражение = текст.RegularExpressions.Regex (шаблон = filePattern)
    
        /// если файл соответствует шаблону
        /// выполняем сопоставление и возвращаем Some async, иначе None
        пусть matchFile (fi: FileInfo) =
            если regex.IsMatch fi.Name, то
                Некоторые (matchPattern textPattern fi)
            еще
                Никто
    
        /// обрабатываем файл, добавляя его асинхронный режим в список
        пусть fFile asyncs (fi: FileInfo) =
            // добавляем в список асинхронных
            (matchFile fi) :: асинхронные
    
        // для каталогов просто пропустить список асинхронных
        пусть fDir asyncs (di: DirectoryInfo) =
            асинхронные
    
        fileSystemItem
        |> Дерево.fold fFile fDir [] // получаем список асинхронных
        |> Seq.choose id // выбираем Somes (где файл был обработан)
        |> Async.Parallel // объединить все асинхронные процессы в один асинхронный
        |> asyncMap (Array.toList >> List.collect id) // объединить массив списков в единый список
      

    Давайте проверим!

      currentDir
    |> grep "fsx" "LinkedList"
    |> Async.RunSynchronously
      

    Результат будет примерно таким:

      "SizeOfTypes.fsx: 120 type LinkedList <'a> = ";
    "SizeOfTypes.fsx: 122 | Ячейка заголовка: 'a * tail: LinkedList <' a>";
    "SizeOfTypes.fsx: 125 let S = size (LinkedList <'a>)";
    "RecursiveTypesAndFold-3.fsx: 15 // LinkedList";
    "RecursiveTypesAndFold-3.fsx: 18 type LinkedList <'a> =";
    "RecursiveTypesAndFold-3.fsx: 20 | Минусы head: 'a * tail: LinkedList <' a>";
    "RecursiveTypesAndFold-3.fsx: 26 module LinkedList =";
    «RecursiveTypesAndFold-3.fsx: 39 list: LinkedList <'a> ";
    "RecursiveTypesAndFold-3.fsx: 64 list: LinkedList <'a> ->";
      

    Это неплохо примерно для 40 строк кода. Эта краткость объясняется тем, что мы используем различные виды -кратной карты и -карты , которые скрывают рекурсию, позволяя сосредоточиться на самой логике сопоставления с образцом.

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

    Исходный код этого примера доступен по этой сути.


    Пример: хранение файловой системы в базе данных

    В следующем примере давайте посмотрим, как сохранить дерево файловой системы в базе данных. Я действительно не знаю, зачем вам это нужно, но принципы одинаково хорошо подходят для хранения любой иерархической структуры, так что я все равно продемонстрирую это!

    Чтобы смоделировать иерархию файловой системы в базе данных, предположим, что у нас есть четыре таблицы:

    • DbDir хранит информацию о каждом каталоге.
    • DbFile хранит информацию о каждом файле.
    • DbDir_File хранит взаимосвязь между каталогом и файлом.
    • DbDir_Dir хранит взаимосвязь между родительским каталогом и дочерним каталогом.

    Вот определения таблиц базы данных:

      СОЗДАТЬ ТАБЛИЦУ DbDir (
    DirId int IDENTITY NOT NULL,
    Имя nvarchar (50) NOT NULL
    )
    
    СОЗДАТЬ ТАБЛИЦУ DbFile (
    FileId int IDENTITY NOT NULL,
    Назовите nvarchar (50) NOT NULL,
    FileSize int NOT NULL
    )
    
    СОЗДАТЬ ТАБЛИЦУ DbDir_File (
    DirId int NOT NULL,
    FileId int NOT NULL
    )
    
    СОЗДАТЬ ТАБЛИЦУ DbDir_Dir (
    ParentDirId int NOT NULL,
    ChildDirId int NOT NULL
    )
      

    Это достаточно просто.Но обратите внимание, что для того, чтобы полностью сохранить каталог вместе с его отношениями с его дочерними элементами, нам сначала нужны идентификаторы всех его дочерних элементов, и каждому дочернему каталогу нужны идентификаторы своих дочерних элементов и так далее.

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

    Реализация функций базы данных

    У нас недостаточно мудрости, чтобы использовать поставщик SQL, поэтому мы написали собственные функции вставки таблиц, например, этот фиктивный:

      /// Вставить запись DbFile
    пусть insertDbFile name (fileSize: int64) =
        пусть id = nextIdentity ()
        printfn "% 10s: вставка id:% i name:% s size:% i" "DbFile" id name fileSize
      

    В реальной базе данных столбец идентификаторов будет автоматически создан для вас, но для этого примера я воспользуюсь небольшой вспомогательной функцией nextIdentity :

      пусть nextIdentity =
        пусть id = ref 0
        веселье () ->
            id: =! id + 1
            !я бы
    
    // контрольная работа
    nextIdentity () // 1
    nextIdentity () // 2
    nextIdentity () // 3
      

    Теперь, чтобы вставить каталог, нам нужно сначала узнать все идентификаторы файлов в каталоге.Это означает, что функция insertDbFile должна вернуть идентификатор, который был сгенерирован.

      /// Вставьте запись DbFile и верните новый идентификатор файла
    пусть insertDbFile name (fileSize: int64) =
        пусть id = nextIdentity ()
        printfn "% 10s: вставка id:% i name:% s size:% i" "DbFile" id name fileSize
        я бы
      

    Но эта логика применима и к каталогам:

      /// Вставьте запись DbDir и верните новый идентификатор каталога
    пусть insertDbDir name =
        пусть id = nextIdentity ()
        printfn "% 10s: вставка id:% i name:% s" "DbDir" id name
        я бы
      

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

    Нет проблем - мы просто воспользуемся типом выбора, чтобы различать их!

      тип PrimaryKey =
        | FileId of int
        | DirId из int
      

    После этого мы можем завершить реализацию функций базы данных:

      /// Вставьте запись DbFile и верните новый PrimaryKey
    пусть insertDbFile name (fileSize: int64) =
        пусть id = nextIdentity ()
        printfn "% 10s: вставка id:% i name:% s size:% i" "DbFile" id name fileSize
        FileId id
    
    /// Вставляем запись DbDir и возвращаем новый PrimaryKey
    пусть insertDbDir name =
        пусть id = nextIdentity ()
        printfn "% 10s: вставка id:% i name:% s" "DbDir" id name
        DirId id
    
    /// Вставить запись DbDir_File
    пусть insertDbDir_File dirId fileId =
        printfn "% 10s: вставка parentDir:% i childFile:% i" "DbDir_File" dirId fileId
    
    /// Вставить запись DbDir_Dir
    пусть insertDbDir_Dir parentDirId childDirId =
        printfn "% 10s: вставка parentDir:% i childDir:% i" "DbDir_Dir" parentDirId childDirId
      

    Работа с катаморфизмом

    Как отмечалось выше, нам нужно использовать cata вместо fold , потому что нам нужны внутренние идентификаторы на каждом шаге.

    Работа с корпусом File проста - просто вставьте его и верните PrimaryKey .

      пусть fFile (fi: FileInfo) =
        insertDbFile fi.Name fi.Length
      

    Функция для обработки случая Directory получит DirectoryInfo и последовательность PrimaryKey от дочерних элементов, которые уже были вставлены.

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

      пусть fDir (di: DirectoryInfo) childIds =
        пусть dirId = insertDbDir di.Имя
        // вставляем потомков
        // возвращаем идентификатор родителю
        dirId
      

    После вставки записи каталога и получения ее идентификатора для каждого дочернего идентификатора мы вставляем либо в таблицу DbDir_File , либо в DbDir_Dir , в зависимости от типа childId .

      пусть fDir (di: DirectoryInfo) childIds =
        let dirId = insertDbDir di.Name
        пусть parentPK = pkToInt dirId
        childIds |> Seq.iter (забавный childId ->
            сопоставить childId с
            | FileId fileId -> insertDbDir_File parentPK fileId
            | DirId childDirId -> insertDbDir_Dir parentPK childDirId
        )
        // возвращаем идентификатор родителю
        dirId
      

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

    Вот весь код в одном куске:

      открытая система
    откройте System.IO
    
    пусть nextIdentity =
        пусть id = ref 0
        веселье () ->
            id: =! id + 1
            !я бы
    
    тип PrimaryKey =
        | FileId of int
        | DirId из int
    
    /// Вставляем запись DbFile и возвращаем новый PrimaryKey
    пусть insertDbFile name (fileSize: int64) =
        пусть id = nextIdentity ()
        printfn "% 10s: вставка id:% i name:% s size:% i" "DbFile" id name fileSize
        FileId id
    
    /// Вставляем запись DbDir и возвращаем новый PrimaryKey
    пусть insertDbDir name =
        пусть id = nextIdentity ()
        printfn "% 10s: вставка id:% i name:% s" "DbDir" id name
        DirId id
    
    /// Вставить запись DbDir_File
    пусть insertDbDir_File dirId fileId =
        printfn "% 10s: вставка parentDir:% i childFile:% i" "DbDir_File" dirId fileId
    
    /// Вставить запись DbDir_Dir
    пусть insertDbDir_Dir parentDirId childDirId =
        printfn "% 10s: вставка parentDir:% i childDir:% i" "DbDir_Dir" parentDirId childDirId
    
    пусть pkToInt primaryKey =
        сопоставить primaryKey с
        | FileId fileId -> fileId
        | DirId dirId -> dirId
    
    пусть insertFileSystemTree fileSystemItem =
    
        пусть fFile (fi: FileInfo) =
            insertDbFile fi.Имя fi.Length
    
        пусть fDir (di: DirectoryInfo) childIds =
            let dirId = insertDbDir di.Name
            пусть parentPK = pkToInt dirId
            childIds |> Seq.iter (забавный childId ->
                сопоставить childId с
                | FileId fileId -> insertDbDir_File parentPK fileId
                | DirId childDirId -> insertDbDir_Dir parentPK childDirId
            )
            // возвращаем идентификатор родителю
            dirId
    
        fileSystemItem
        |> Tree.cata fFile fDir
      

    А теперь проверим:

      // получаем текущий каталог как дерево
    пусть currentDir = fromDir (DirectoryInfo ("."))
    
    // вставляем в базу
    currentDir
    |> insertFileSystemTree
      

    Результат должен выглядеть примерно так:

      DbDir: вставка идентификатора: 41 имя: FoldAndRecursiveTypes
        DbFile: вставка id: 42 имя: Fold.fsx размер: 8315
    DbDir_File: вставка parentDir: 41 childFile: 42
        DbFile: вставка идентификатора: 43 имя: FoldAndRecursiveTypes.fsproj размер: 3680
    DbDir_File: вставка parentDir: 41 childFile: 43
        DbFile: вставка идентификатора: 44 имя: FoldAndRecursiveTypes.sln размер: 1010
    DbDir_File: вставка parentDir: 41 childFile: 44
    ...
         DbDir: вставка идентификатора: 57 имя: bin
         DbDir: вставка идентификатора: 58 имя: Отладка
     DbDir_Dir: вставка parentDir: 57 childDir: 58
     DbDir_Dir: вставка parentDir: 41 childDir: 57
      

    Вы можете видеть, что идентификаторы генерируются по мере итерации файлов, и что за каждой вставкой DbFile следует вставка DbDir_File .

    Исходный код этого примера доступен по этой сути.


    Пример: сериализация дерева в JSON

    Давайте посмотрим на еще одну распространенную проблему: сериализацию и десериализацию дерева в JSON, XML или какой-либо другой формат.

    Давайте снова воспользуемся доменом Gift, но на этот раз смоделируем тип Gift в виде дерева. Это означает, что мы можем положить в коробку более одной вещи!

    Моделирование подарочного домена в виде дерева

    Вот еще раз основные типы, но обратите внимание, что последний тип Gift определен как дерево:

      type Book = {title: string; price: decimal}
    тип ChocolateType = Темный | Молоко | Семьдесят процентов
    тип Шоколад = {chocType: ChocolateType; price: decimal}
    
    тип WrappingPaperStyle =
        | С днем ​​рождения
        | Счастливых праздников
        | SolidColor
    
    // единые данные для нерекурсивных случаев
    тип GiftContents =
        | Книга Книги
        | Шоколад из шоколада
    
    // единые данные для рекурсивных случаев
    тип GiftDecoration =
        | Завернутый из WrappingPaperStyle
        | В штучной упаковке
        | С картой строки
    
    тип Gift = Tree 
      

    Как обычно, мы можем создать несколько вспомогательных функций, которые помогут создать подарок :

      пусть fromBook book =
        LeafNode (Книжная книга)
    
    пусть fromChoc choc =
        LeafNode (шоколадный шоколад)
    
    пусть wrapInPaper paperStyle innerGift =
        let container = Стиль бумаги в обертке
        InternalNode (контейнер, [innerGift])
    
    пусть putInBox innerGift =
        let container = В штучной упаковке
        InternalNode (контейнер, [innerGift])
    
    пусть withCard сообщение innerGift =
        let container = сообщение WithACard
        InternalNode (контейнер, [innerGift])
    
    пусть putTwoThingsInBox innerGift innerGift2 =
        let container = В штучной упаковке
        InternalNode (контейнер, [innerGift; innerGift2])
      

    И мы можем создать некоторые образцы данных:

      пусть wolfHall = {title = "Волчий зал"; цена = 20м}
    пусть yummyChoc = {chocType = SeventyPercent; цена = 5м}
    
    пусть birthdayPresent =
        волкхолл
        |> из книги
        |> wrapInPaper С Днем Рождения
        |> Открытка "С Днем Рождения"
    
    пусть christmasPresent =
        yummyChoc
        |> fromChoc
        |> putInBox
        |> wrapInPaper HappyHolidays
    
    пусть twoBirthdayPresents =
        let thing1 = wolfHall |> fromBook
        пусть вещь2 = yummyChoc |> fromChoc
        putTwoThingsInBox thing1 thing2
        |> wrapInPaper С Днем Рождения
    
    пусть twoWrappedPresentsInBox =
        let thing1 = wolfHall |> fromBook |> wrapInPaper HappyHolidays
        let thing2 = yummyChoc |> fromChoc |> wrapInPaper HappyBirthday
        putTwoThingsInBox thing1 thing2
      

    Функции, такие как description , теперь должны обрабатывать список внутренних текстов, а не один.Мы просто объединим строки с помощью разделителя и :

      пусть описание gift =
    
        пусть fLeaf leafData =
            сопоставить leafData с
            | Книжная книга ->
                sprintf "'% s'" book.title
            | Шоколадный шоколад ->
                sprintf "% A шоколад" choc.chocType
    
        пусть fNode nodeData innerTexts =
            let innerText = String.concat "&" innerTexts
            сопоставить nodeData с
            | Завернутый стиль ->
                sprintf "% s, завернутый в бумагу% A" стиль innerText
            | В штучной упаковке ->
                sprintf "% s в коробке" innerText
            | Сообщение WithACard ->
                sprintf "% s с карточкой"% s "" innerText сообщение
    
        // основной вызов
        Дерево.cata fLeaf fNode подарок
      

    Наконец, мы можем проверить, что функция по-прежнему работает, как и раньше, и что несколько элементов обрабатываются правильно:

      день рожденияПодарок |> описание
    // "Волчий зал" завернутый в бумагу HappyBirthday с открыткой с надписью "Happy Birthday" "
    
    christmasPresent |> описание
    // "Семидесятипроцентный шоколад в коробке, завернутой в бумагу HappyHolidays"
    
    twoBirthdayPresents |> описание
    // "Шоколад 'Wolf Hall' и SeventyPercent в коробке
    // завернутый в бумагу HappyBirthday "
    
    twoWrappedPresentsInBox |> описание
    // "Волчий зал" завернутый в бумагу HappyHolidays
    // & SeventyPercent шоколад, завернутый в бумагу HappyBirthday
    //   в коробке"
      

    Наш тип Gift состоит из множества различаемых объединений.По моему опыту, они плохо сериализуются. Фактически, большинство сложных типов плохо сериализуются!

    Мне нравится определять типы DTO, которые явно предназначены для хорошей сериализации. На практике это означает, что типы DTO ограничены следующим образом:

    • Следует использовать только типы записей.
    • Поля записи должны состоять только из примитивных значений, таких как int , string и bool .

    Таким образом, мы получаем и другие преимущества:

    Мы получаем контроль над выходом сериализации. Эти типы данных обрабатываются одинаково большинством сериализаторов, в то время как «Странные» вещи, такие как союзы, могут по-разному интерпретироваться разными библиотеками.

    Мы лучше контролируем обработку ошибок. Мое правило номер один при работе с сериализованными данными - «никому не доверять». Очень часто данные структурированы правильно, но недопустимы для домена: предположительно ненулевые строки равны нулю, строки слишком длинные, целые числа находятся за пределами правильных границ и т. д.

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

    Итак, давайте определим некоторые типы DTO для нашего домена. Каждый тип DTO будет соответствовать типу домена, поэтому давайте начнем с GiftContents . Мы определим соответствующий тип DTO с именем GiftContentsDto следующим образом:

      []
    type GiftContentsDto = {
        Дискриминатор: строка // "Книга" или "Шоколад"
        // только для случая "Книга"
        bookTitle: строка
        // только для случая "Шоколад"
        chocolateType: string // один из "Dark" "Milk" "SeventyPercent"
        // на все случаи
        цена: десятичная
        }
      

    Очевидно, это сильно отличается от исходного GiftContents , поэтому давайте посмотрим на различия:

    • Во-первых, он имеет CLIMutableAttribute , который позволяет десериализаторам создавать их с помощью отражения.
    • Во-вторых, он имеет дискриминатор , который указывает, какой вариант исходного типа объединения используется. Очевидно, эта строка может быть установлена ​​на что угодно, поэтому при преобразовании из DTO обратно в тип домена мы должны это тщательно проверить!
    • Далее следует ряд полей, по одному для каждого возможного элемента данных, который необходимо сохранить. Например, в случае Book нам понадобится bookTitle , в то время как в случае Chocolate нам нужен шоколадный тип.И, наконец, поле price , которое есть в обоих типах. Обратите внимание, что тип шоколада также хранится в виде строки, и поэтому он также потребует специальной обработки при преобразовании из DTO в домен.

    Тип GiftDecorationDto создается таким же образом, с дискриминатором и строками, а не объединениями.

      []
    type GiftDecorationDto = {
        Дискриминатор: строка // "С оболочкой", "В штучной упаковке" или "С картой"
        // только для случая "Wrapped"
        wrappingPaperStyle: string // «HappyBirthday», «HappyHolidays» или «SolidColor»
        // только для случая "WithACard"
        сообщение: строка
        }
      

    Наконец, мы можем определить тип GiftDto как дерево, состоящее из двух типов DTO:

      тип GiftDto = Tree 
      

    Шаг 2: преобразование подарка

    в подарок Dto

    Теперь, когда у нас есть этот тип DTO, все, что нам нужно сделать, это использовать дерево .map , чтобы преобразовать из Gift в GiftDto . И для этого нам нужно создать две функции: одну, которая преобразует из GiftContents в GiftContentsD в и одну который преобразует GiftDecoration в GiftDecorationDto .

    Вот полный код для giftToDto , который не требует пояснений:

      пусть giftToDto (подарок: Gift): GiftDto =
    
        пусть fLeaf leafData: GiftContentsDto =
            сопоставить leafData с
            | Книжная книга ->
                {Дискриминатор = "Книга"; bookTitle = книга.заглавие; chocolateType = null; price = book.price}
            | Шоколадный шоколад ->
                let chocolateType = sprintf "% A" choc.chocType
                {Дискриминатор = "Шоколад"; bookTitle = null; chocolateType = chocolateType; price = choc.price}
    
        пусть fNode nodeData: GiftDecorationDto =
            сопоставить nodeData с
            | Завернутый стиль ->
                let wrappingPaperStyle = sprintf стиль "% A"
                {Дискриминатор = "Завернутый"; wrappingPaperStyle = wrappingPaperStyle; message = null}
            | В штучной упаковке ->
                {Дискриминатор = "В штучной упаковке"; wrappingPaperStyle = null; message = null}
            | Сообщение WithACard ->
                {Дискриминатор = "WithACard"; wrappingPaperStyle = null; message = message}
    
        // основной вызов
        Дерево.карта fLeaf fNode подарок
      

    Вы можете видеть, что корпус ( Book , Chocolate и т. Д.) Превращается в строку дискриминатора , а chocolateType также превращается в строку, просто как объяснено выше.

    Шаг 3: определение дерева

    Выше я сказал, что хорошим DTO должен быть тип записи. Итак, мы преобразовали узлы дерева, но само дерево является типом объединения! Нам также нужно преобразовать тип Tree , скажем, в тип TreeDto .

    Как мы можем это сделать? Так же, как и для подарочных типов DTO, мы создадим тип записи, который будет содержать все данные для обоих случаев. Мы могли бы использовать дискриминатор field, как мы делали раньше, но на этот раз, поскольку есть только два варианта: лист и внутренний узел, я просто проверю, являются ли значения нулевыми или нет при десериализации. Если конечное значение не равно нулю, тогда запись должна представлять случай LeafNode , в противном случае запись должна представлять случай InternalNode .

    Вот определение типа данных:

      /// DTO, представляющий дерево
    /// Выбор Leaf / Node превращается в запись
    []
    type TreeDto <'LeafData,' NodeData> = {
        leafData: 'LeafData
        nodeData: 'NodeData
        поддеревья: TreeDto <'LeafData,' NodeData> []}
      

    Как и раньше, тип имеет атрибут CLIMutableAttribute . И, как и раньше, у типа есть поля для хранения данных из всех возможных вариантов. Поддеревья хранятся в виде массива, а не последовательности - это делает сериализатор счастливым!

    Чтобы создать TreeDto , мы используем нашего старого друга cata , чтобы собрать запись из обычного Tree .

      /// Преобразование дерева в деревоDto
    пусть treeToDto tree: TreeDto <'LeafData,' NodeData> =
    
        пусть fLeaf leafData =
            let nodeData = Unchecked.defaultof <'NodeData>
            пусть поддеревья = [||]
            {leafData = leafData; nodeData = nodeData; subtrees = поддеревья}
    
        пусть fNode nodeData subtrees =
            let leafData = Unchecked.defaultof <'NodeData>
            let subtrees = subtrees |> Seq.toArray
            {leafData = leafData; nodeData = nodeData; subtrees = поддеревья}
    
        // рекурсивно построить TreeDto
        Дерево.cata fLeaf fNode tree
      

    Обратите внимание, что в F # записи не допускают значения NULL, поэтому я использую Unchecked.defaultof <'NodeData> , а не null , чтобы указать отсутствующие данные.

    Также обратите внимание, что я предполагаю, что LeafData или NodeData являются ссылочными типами. Если LeafData или NodeData когда-либо являются типами значений, такими как int или bool , тогда этот подход не работает, потому что вы не сможете определить разницу между значением по умолчанию и отсутствующим значением.В этом случае я бы, как и раньше, переключился на поле дискриминатора.

    В качестве альтернативы я мог бы использовать IDictionary . Это было бы менее удобно для десериализации, но позволило бы избежать проверки на нуль.

    Шаг 4. Сериализация дерева

    в

    Наконец, мы можем сериализовать TreeDto с помощью сериализатора JSON.

    В этом примере я использую встроенный DataContractJsonSerializer , поэтому мне не нужно зависимость от пакета NuGet.Есть и другие сериализаторы JSON, которые могут быть лучше для серьезного проекта.

      #r "System.Runtime.Serialization.dll"
    
    откройте System.Runtime.Serialization
    откройте System.Runtime.Serialization.Json
    
    пусть toJson (o: 'a) =
        let сериализатор = новый DataContractJsonSerializer (typeof <'a>)
        пусть кодировка = System.Text.UTF8Encoding ()
        используйте stream = new System.IO.MemoryStream ()
        сериализатор.WriteObject (поток, o)
        stream.Close ()
        encoding.GetString (stream.ToArray ())
      

    Шаг 5: Сборка трубопровода

    Итак, сложив все вместе, мы получаем следующий конвейер:

    • Преобразуйте Gift в GiftDto , используя giftToDto ,
      , то есть используйте Tree.map перейти от Tree к Tree
    • Преобразуйте дерево в TreeDto , используя treeToDto ,
      , то есть используйте Tree.cata для перехода от Tree к TreeDto Сериализовать TreeDto в строку JSON

    Вот пример кода:

      let goodJson = christmasPresent |> giftToDto |> treeToDto |> toJson
      

    А вот как выглядит вывод JSON:

      {
      "leafData @": ноль,
      "nodeData @": {
        "discinator @": "Завернутый",
        "message @": null,
        "wrappingPaperStyle @": "HappyHolidays"
      },
      "поддеревья @": [
        {
          "leafData @": ноль,
          "nodeData @": {
            "Дискриминатор @": "В штучной упаковке",
            "message @": null,
            "wrappingPaperStyle @": нуль
          },
          "поддеревья @": [
            {
              "leafData @": {
                "bookTitle @": null,
                "chocolateType @": "SeventyPercent",
                "discinator @": "Шоколад",
                "цена @": 5
              },
              "nodeData @": ноль,
              "поддеревья @": []
            }
          ]
        }
      ]
    }
      

    Уродливые знаки @ на именах полей являются артефактом сериализации типа записи F #.Это можно исправить, приложив немного усилий, но сейчас я не буду беспокоиться!

    Исходный код этого примера доступен по этому адресу


    Пример: десериализация дерева из JSON

    Теперь, когда мы создали JSON, как насчет того, чтобы пойти другим путем и загрузить его в подарок ?

    Просто! Нам просто нужно перевернуть конвейер:

    • Десериализовать строку JSON в TreeDto .
    • Преобразуйте TreeDto в Tree , чтобы использовать dtoToTree ,
      , то есть перейти от TreeDto к Tree . Мы не можем использовать для этого cata - нам придется создать небольшой рекурсивный цикл.
    • Преобразуйте GiftDto в Gift с помощью dtoToGift ,
      , то есть используйте Tree.map , чтобы перейти от Tree к Tree .

    Шаг 1: десериализация дерева

    Мы можем десериализовать TreeDto с помощью сериализатора JSON.

      пусть fromJson <'a> str =
        let сериализатор = новый DataContractJsonSerializer (typeof <'a>)
        пусть кодировка = System.Text.UTF8Encoding ()
        используйте stream = new System.IO.MemoryStream (encoding.GetBytes (s = str))
        let obj = serializer.ReadObject (поток)
        obj:?> 'a
      

    Что делать, если десериализация не удалась? На данный момент мы проигнорируем любую обработку ошибок и позволим исключению распространиться.

    Шаг 2: Преобразование

    TreeDto в Tree

    Чтобы преобразовать TreeDto в Tree , мы рекурсивно перебираем запись и ее поддеревья, превращая каждое из них в InternalNode или LeafNode , в зависимости от того, является ли соответствующее поле нулевым или нет.

      let rec dtoToTree (treeDto: TreeDto <'Leaf,' Node>): Tree <'Leaf,' Node> =
        let nullLeaf = Не отмечено.defaultof <'Лист>
        let nullNode = Unchecked.defaultof <'Узел>
    
        // проверяем наличие nodeData
        если treeDto.nodeData <> nullNode, то
            если treeDto.subtrees = null, то
                failwith "поддеревья не должны быть нулевыми, если присутствуют данные узла"
            еще
                let subtrees = treeDto.subtrees |> Array.map dtoToTree
                InternalNode (treeDto.nodeData, поддеревья)
        // проверяем, есть ли листовые данные
        elif treeDto.leafData <> nullLeaf тогда
            LeafNode (treeDto.листДанные)
        // если оба отсутствуют, то ошибка
        еще
            сбой с "ожиданием данных листа или узла"
      

    Как видите, ряд вещей может пойти не так:

    • Что делать, если поля leafData и nodeData оба пустые?
    • Что делать, если поле nodeData не равно нулю, а поле поддеревьев имеет значение ?

    Опять же, мы проигнорируем любую обработку ошибок и просто выбрасываем исключения (пока).

    Вопрос: Можно ли создать cata для TreeDto , который упростит этот код? Стоило ли оно того?

    Шаг 3: преобразование

    GiftDto в Gift

    Теперь у нас есть правильное дерево, мы можем снова использовать Tree.map , чтобы преобразовать каждый лист и внутренний узел из DTO в правильный тип домена.

    Это означает, что нам нужны функции, которые сопоставляют GiftContentsDto с GiftContents и GiftDecorationDto с GiftDecoration .

    Вот полный код - это намного сложнее, чем идти в обратном направлении!

    Код можно сгруппировать следующим образом:

    • Вспомогательные методы (например, strToChocolateType ), которые преобразуют строку в правильный тип домена и выдают исключение, если введенные данные недействительны.
    • Методы преобразования регистра
    • (например, bookFromDto ), которые преобразуют весь DTO в регистр.
    • И, наконец, сама функция dtoToGift .Он смотрит на поле дискриминатора , чтобы узнать, какой преобразователь регистров вызывать, и выдает исключение, если значение дискриминатора не распознается.
      let strToBookTitle str =
        сопоставить str с
        | null -> failwith "BookTitle не должен быть нулевым"
        | _ -> ул.
    
    пусть strToChocolateType str =
        сопоставить str с
        | «Темный» -> Темный
        | «Молоко» -> Молоко
        | «Семьдесят процентов» -> Семьдесят процентов
        | _ -> failwithf "Тип шоколада% s не распознан" str
    
    пусть strToWrappingPaperStyle str =
        сопоставить str с
        | «С Днем Рождения» -> С Днем Рождения
        | "HappyHolidays" -> HappyHolidays
        | «SolidColor» -> SolidColor
        | _ -> failwithf "WrappingPaperStyle% s не распознан" str
    
    пусть strToCardMessage str =
        сопоставить str с
        | null -> ошибка "CardMessage не может быть нулевым"
        | _ -> ул.
    
    пусть bookFromDto (dto: GiftContentsDto) =
        пусть bookTitle = strToBookTitle dto.Заголовок книги
        Книга {title = bookTitle; price = dto.price}
    
    пусть шоколадFromDto (dto: GiftContentsDto) =
        let chocType = strToChocolateType dto.chocolateType
        Шоколад {chocType = chocType; price = dto.price}
    
    пусть wrappedFromDto (dto: GiftDecorationDto) =
        пусть wrappingPaperStyle = strToWrappingPaperStyle dto.wrappingPaperStyle
        Упаковочная упаковка
    
    пусть boxedFromDto (dto: GiftDecorationDto) =
        В штучной упаковке
    
    пусть withACardFromDto (dto: GiftDecorationDto) =
        let message = strToCardMessage dto.сообщение
        Сообщение WithACard
    
    /// Преобразование GiftDto в подарок
    пусть dtoToGift (giftDto: GiftDto): Gift =
    
        пусть fLeaf (leafDto: GiftContentsDto) =
            сопоставить leafDto.discriminator с
            | "Книга" -> bookFromDto leafDto
            | "Шоколад" -> шоколад
            | _ -> failwithf "Неизвестный листовой дискриминатор '% s'" leafDto.discriminator
    
        пусть fNode (nodeDto: GiftDecorationDto) =
            сопоставить nodeDto.discriminator с
            | "Wrapped" -> wrappedFromDto nodeDto
            | "В штучной упаковке" -> в штучной упаковкеFromDto nodeDto
            | "WithACard" -> withACardFromDto nodeDto
            | _ -> failwithf "Дискриминатор неизвестного узла '% s'" nodeDto.дискриминатор
    
        // отображаем дерево
        Tree.map fLeaf fNode giftDto
      

    Шаг 4: Сборка трубопровода

    Теперь мы можем собрать конвейер, который принимает строку JSON и создает подарок .

      let goodGift = goodJson |> fromJson |> dtoToTree |> dtoToGift
    
    // проверяем, что описание не изменилось
    goodGift |> описание
    // "Семидесятипроцентный шоколад в коробке, завернутой в бумагу HappyHolidays"
      

    Это работает нормально, но обработка ошибок ужасна!

    Посмотрите, что произойдет, если мы немного повредим JSON:

      пусть badJson1 = goodJson.Заменить ("leafData", "leafDataXX")
    
    пусть badJson1_result = badJson1 |> fromJson |> dtoToTree |> dtoToGift
    // Исключение «Тип контракта данных 'TreeDto' не может быть десериализован, потому что требуемый элемент данных 'leafData @' не найден».
      

    Получаем некрасивое исключение.

    А что если дискриминатор неправильный?

      let badJson2 = goodJson.Replace ("Wrapped", "Wrapped2")
    
    пусть badJson2_result = badJson2 |> fromJson |> dtoToTree |> dtoToGift
    // Исключение «Дискриминатор неизвестного узла 'Wrapped2'»
      

    или одно из значений WrappingPaperStyle DU?

      пусть badJson3 = goodJson.Заменить ("HappyHolidays", "HappyHolidays2")
    пусть badJson3_result = badJson3 |> fromJson |> dtoToTree |> dtoToGift
    // Исключение «WrappingPaperStyle HappyHolidays2 не распознано»
      

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

    Как мы можем это сделать, мы обсудим в следующем разделе.

    Исходный код этого примера доступен по этой сути.


    Пример: десериализация дерева из JSON - с обработкой ошибок

    Чтобы решить проблему с обработкой ошибок, мы будем использовать тип Result , показанный ниже:

      тип Результат <'a> =
        | Успех
        | Ошибка списка строк
      

    Я не буду здесь объяснять, как это работает.Если вы не знакомы с этим подходом, прочтите мой пост или посмотрите мой доклад на тему функциональной обработки ошибок.

    Давайте вернемся ко всем шагам из предыдущего раздела и используем результат , результат , а не выбрасывать исключения.

    Шаг 1: десериализация дерева

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

      пусть fromJson <'a> str =
        пытаться
            let сериализатор = новый DataContractJsonSerializer (typeof <'a>)
            пусть кодировка = System.Text.UTF8Encoding ()
            используйте stream = new System.IO.MemoryStream (encoding.GetBytes (s = str))
            let obj = serializer.ReadObject (поток)
            obj:?> 'a
            |> Result.retn
        с участием
        | бывший ->
            Result.failWithMsg ex.Message
      

    Подпись из Json теперь является строкой -> Результат <'a> .

    Шаг 2: Преобразование

    TreeDto в Tree

    Как и раньше, мы преобразуем TreeDto в Tree путем рекурсивного цикла по записи и ее поддеревьям, превращая каждое из них в InternalNode или LeafNode . Однако на этот раз мы используем результат , результат , для обработки любых ошибок.

      let rec dtoToTreeOfResults (treeDto: TreeDto <'Leaf,' Node>): Tree , Result <' Node >> =
        let nullLeaf = Не отмечено.defaultof <'Лист>
        let nullNode = Unchecked.defaultof <'Узел>
    
        // проверяем наличие nodeData
        если treeDto.nodeData <> nullNode, то
            если treeDto.subtrees = null, то
                LeafNode <| Result.failWithMsg "поддеревья не должны быть нулевыми, если присутствуют данные узла"
            еще
                let subtrees = treeDto.subtrees |> Array.map dtoToTreeOfResults
                InternalNode (Result.retn treeDto.nodeData, поддеревья)
        // проверяем, есть ли листовые данные
        elif treeDto.leafData <> nullLeaf тогда
            LeafNode <| Результат.retn (treeDto.leafData)
        // если оба отсутствуют, то ошибка
        еще
            LeafNode <| Result.failWithMsg "ожидание данных листа или узла"
    
    // val dtoToTreeOfResults:
    // treeDto: TreeDto <'Leaf,' Node> -> Tree , Result <' Node >>
      

    Но э-э, теперь у нас есть дерево , где каждый внутренний узел и лист обернут в Результат . Это дерево из Результатов ! Фактическая уродливая подпись такова: Дерево <Результат <'Лист>, Результат <' Узел >> .

    Но этот тип бесполезен в его нынешнем виде - то, что нам на самом деле нужно , - это объединить все ошибки вместе и вернуть Result , содержащий Tree .

    Как мы можем преобразовать дерево результатов в дерево результатов?

    Ответ заключается в использовании функции последовательности , которая «меняет местами» два типа. Вы можете больше узнать о последовательности в моей серии статей о возвышенных мирах.

    Обратите внимание, что мы также можем использовать немного более сложный вариант traverse , чтобы объединить карту и последовательность в один шаг, но для целей этой демонстрации легче понять, если шаги будут разделены.

    Нам нужно создать нашу собственную последовательность функцию для комбинации Дерево / Результат. К счастью, создание функции последовательности это механический процесс:

    • Для нижнего типа ( Результат ) нам нужно определить , применить и вернуть функции . Подробнее о том, что означает apply , см. Здесь.
    • Для более высокого типа ( Tree ) нам нужна функция cata , что мы и делаем.
    • В катаморфизме каждый конструктор более высокого типа ( LeafNode и InternalNode в данном случае) заменяется эквивалентом, который «поднимается» до типа Result (например,грамм. retn LeafNode <*> данные )

    Вот настоящий код - не волнуйтесь, если вы не можете его сразу понять. К счастью, нам нужно написать его только один раз для каждой комбинации. типов, поэтому для любого вида комбинации дерева / результата в будущем мы настроены!

      /// Преобразование дерева результатов в дерево результатов
    пусть sequenceTreeOfResult tree =
        // с нижнего уровня
        let (<*>) = Result.apply
        let retn = Result.retn
    
        // с проходимого уровня
        пусть fLeaf data =
            retn LeafNode <*> данные
    
        пусть подэлементы данных fNode =
            let makeNode data items = InternalNode (данные, элементы)
            let subItems = Результат.Подэлементы sequenceSeq
            retn makeNode <*> data <*> подэлементы
    
        // делаем обход
        Tree.cata fLeaf fNode tree
    
    // val sequenceTreeOfResult:
    // дерево: Дерево <Результат <'a>, Результат <' b >> -> Результат <Дерево <'a,' b >>
      

    Наконец, фактическая функция dtoToTree проста - просто отправьте treeDto с по dtoToTreeOfResults , а затем используйте sequenceTreeOfResult для преобразовать окончательный результат в Result > , а это как раз то, что нам нужно.

      пусть dtoToTree treeDto =
        treeDto |> dtoToTreeOfResults |> sequenceTreeOfResult
    
    // val dtoToTree: treeDto: TreeDto <'a,' b> -> Результат >
      

    Шаг 3. Преобразование подарка

    GiftDto в подарок

    Снова мы можем использовать Tree.map для преобразования каждого листа и внутреннего узла из DTO в правильный тип домена.

    Но наши функции будут обрабатывать ошибки, поэтому им необходимо отобразить GiftContentsD на в Result и GiftDecorationDto в Result . Это снова приводит к дереву результатов, поэтому нам придется снова используйте sequenceTreeOfResult , чтобы вернуть ему правильную форму Result > .

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

      let strToBookTitle str =
        сопоставить str с
        | null -> Result.failWithMsg "Название книги не должно быть пустым"
        | _ -> Result.retn str
    
    пусть strToChocolateType str =
        сопоставить str с
        | «Темный» -> Результат.retn Темный
        | «Молоко» -> Result.retn Milk
        | "SeventyPercent" -> Result.retn SeventyPercent
        | _ -> Result.failWithMsg (sprintf "Тип шоколада% s не распознан" str)
    
    пусть strToWrappingPaperStyle str =
        сопоставить str с
        | «HappyBirthday» -> Результат.retn HappyBirthday
        | "HappyHolidays" -> Result.retn HappyHolidays
        | «SolidColor» -> Result.retn SolidColor
        | _ -> Result.failWithMsg (sprintf "WrappingPaperStyle% s не распознан" str)
    
    пусть strToCardMessage str =
        сопоставить str с
        | null -> Result.failWithMsg "CardMessage не может быть нулевым"
        | _ -> Result.retn str
      

    Методы преобразования регистра должны создавать Book или Chocolate из параметров, которые имеют Result s, а не нормальные значения.Это где могут помочь подъемные функции, такие как Result.lift2 . Подробнее о том, как это работает, читайте в этом посте о подъеме и этом о валидации с помощью аппликативов.

      пусть bookFromDto (dto: GiftContentsDto) =
        пусть книга bookTitle цена =
            Книга {title = bookTitle; цена = цена}
    
        let bookTitle = strToBookTitle dto.bookTitle
        let price = Result.retn dto.price
        Result.lift2 книга книга
    
    пусть шоколадFromDto (dto: GiftContentsDto) =
        пусть choc chocType price =
            Шоколад {chocType = chocType; цена = цена}
    
        пусть chocType = strToChocolateType dto.шоколадТип
        let price = Result.retn dto.price
        Result.lift2 choc chocТип цена
    
    пусть wrappedFromDto (dto: GiftDecorationDto) =
        пусть wrappingPaperStyle = strToWrappingPaperStyle dto.wrappingPaperStyle
        Result.map Wrapped wrappingPaperStyle
    
    пусть boxedFromDto (dto: GiftDecorationDto) =
        Result.retn в штучной упаковке
    
    пусть withACardFromDto (dto: GiftDecorationDto) =
        let message = strToCardMessage dto.message
        Result.map WithACard сообщение
      

    И, наконец, сама функция dtoToGift изменяется, чтобы возвращать результат , если дискриминатор недействителен.

    Как и раньше, это сопоставление создает дерево результатов, поэтому мы направляем вывод Tree.map с по sequenceTreeOfResult

      `Tree.map fLeaf fNode giftDto |> sequenceTreeOfResult`
      

    … чтобы вернуть результат дерева.

    Вот полный код для dtoToGift :

      открыть TreeDto_WithErrorHandling
    
    /// Преобразуем GiftDto в результат 
    let dtoToGift (giftDto: GiftDto): Результат <Подарок> =
    
        пусть fLeaf (leafDto: GiftContentsDto) =
            сопоставьте листДто.дискриминатор с
            | "Книга" -> bookFromDto leafDto
            | "Шоколад" -> шоколад
            | _ -> Result.failWithMsg (sprintf "Неизвестный листовой дискриминатор '% s'" leafDto.discriminator)
    
        пусть fNode (nodeDto: GiftDecorationDto) =
            сопоставить nodeDto.discriminator с
            | "Wrapped" -> wrappedFromDto nodeDto
            | "В штучной упаковке" -> в штучной упаковкеFromDto nodeDto
            | "WithACard" -> withACardFromDto nodeDto
            | _ -> Result.failWithMsg (sprintf "Дискриминатор неизвестного узла '% s'" nodeDto.дискриминатор)
    
        // отображаем дерево
        Tree.map fLeaf fNode giftDto |> sequenceTreeOfResult
      

    Сигнатура типа dtoToGift изменилась - теперь он возвращает Result , а не просто Gift .

      // val dtoToGift: GiftDto -> Результат 
      

    Шаг 4: Сборка трубопровода

    Теперь мы можем собрать конвейер, который принимает строку JSON и создает подарок .

    Но для работы с новым кодом обработки ошибок необходимы изменения:

    • Функция fromJson возвращает Result , но следующая функция в конвейере ( dtoToTree ) ожидает в качестве входных данных обычный TreeDto .
    • Точно так же dtoToTree возвращает Result , но следующая функция в конвейере ( dtoToGift ) ожидает в качестве входных данных обычное дерево .

    В обоих случаях Результат.bind может использоваться для решения этой проблемы несоответствия вывода / ввода. См. Здесь для более подробного обсуждения bind.

    Хорошо, давайте попробуем десериализовать строку goodJson , которую мы создали ранее.

      let goodGift = goodJson |> fromJson |> Result.bind dtoToTree |> Result.bind dtoToGift
    
    // проверяем, что описание не изменилось
    goodGift |> описание
    // Успех "Семидесятипроцентный шоколад в коробке, завернутой в бумагу HappyHolidays"
      

    Ничего страшного.

    Посмотрим, улучшилась ли обработка ошибок сейчас. Мы снова повредим JSON:

      пусть badJson1 = goodJson.Replace ("leafData", "leafDataXX")
    
    let badJson1_result = badJson1 |> fromJson |> Result.bind dtoToTree |> Result.bind dtoToGift
    // Ошибка ["Тип контракта данных 'TreeDto' не может быть десериализован, потому что требуемый элемент данных 'leafData @' не найден."]
      

    Отлично! Получаем красивый корпус Failure .

    А что если дискриминатор неправильный?

      пусть badJson2 = goodJson.Заменить ("Обернутый", "Обернутый2")
    let badJson2_result = badJson2 |> fromJson |> Result.bind dtoToTree |> Result.bind dtoToGift
    // Ошибка ["Дискриминатор неизвестного узла 'Wrapped2'"]
      

    или одно из значений WrappingPaperStyle DU?

      let badJson3 = goodJson.Replace ("HappyHolidays", "HappyHolidays2")
    let badJson3_result = badJson3 |> fromJson |> Result.bind dtoToTree |> Result.bind dtoToGift
    // Ошибка ["WrappingPaperStyle HappyHolidays2 не распознан"]
      

    Опять же приятно Отказ случаев.

    Что очень хорошо (и это то, чего не может предложить подход к обработке исключений), так это то, что если есть При наличии более одной ошибки различные ошибки можно объединить, чтобы мы получили список из всех ошибок, которые пошли не так, а не только по одной ошибке за раз.

    Давайте посмотрим на это в действии, добавив две ошибки в строку JSON:

      // создаем две ошибки
    let badJson4 = goodJson.Replace ("HappyHolidays", "HappyHolidays2")
                           .Заменить ("Семьдесят процентов", "Семьдесят процентов2")
    let badJson4_result = badJson4 |> fromJson |> Result.bind dtoToTree |> Result.bind dtoToGift
    // Ошибка ["WrappingPaperStyle HappyHolidays2 не распознан";
    // "Тип шоколада SeventyPercent2 не распознан"]
      

    В целом, я бы сказал, что это успех!

    Исходный код этого примера доступен по этой сути.


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

    Эта серия оказалась намного длиннее, чем я планировал, так что спасибо, что дочитали до конца! Ваше здоровье!

    Family Finder - Функция поиска семейных пар - Учебный центр FamilyTreeDNA

    Функция поиска семьи - сопоставление семьи позволяет быстро и по отдельности просматривать подтвержденные совпадения по материнской и отцовской линии с помощью функции поиска семьи.Эта функция назначает материнских значков или отцовских значкам Family Finder клиента - сопоставляет список на основе поэтапного сопоставления с близкими родственниками в сочетании со специальным порогом сопоставления семьи.

    Чтобы воспользоваться этой функцией:

    1. Инструмент «Подбор семьи» не ограничивается родителями и использует всех, кто прошел тест «Поиск семьи» и в настоящее время связан с вашим деревом от родителя до третьего кузена.

      • Мы планируем продолжить работу над Family Matching и добавлением более отдаленных отношений.

      • Family Matching продолжает заполнять информацию при связывании большего количества совпадений за пределами связанного диапазона непосредственных родительских отношений. Мы всегда рекомендуем связывать всех членов вашей семьи, даже если конкретная связь в настоящее время не используется, как это может быть в будущем.

      • Взаимоотношения проверяются на основе диапазона Family Finder с помощью формулы + в зависимости от расстояния.Например, система не будет использовать кого-либо в качестве родителя, если он считается двоюродным братом 2 и .

      • Family Matching не заполняется на основе отношений, указанных пользователями в поле «Known Relationship», а скорее назначает материнские и отцовские значки только на основе одного или нескольких связанных наборов, алгоритма поэтапного сопоставления и порога сопоставления семьи.

    2. Система сопоставления семейств не основана на функции «Общее с / не-общее с», которая полностью основана на списке сопоставлений.Вместо этого Family Matching основывается на поэтапных блоках, обнаруживаемых между отношениями, учет поэтапной информации важен, поскольку он гарантирует, что блок не только имеет одинаковый размер и находится в одном месте, но также передается одними и теми же аллелями.

    3. Хотя сопоставление выполняется с использованием различных формул, основанных на поэтапной ДНК, в настоящее время существует один порог, который жестко запрограммирован. Текущая версия системы Family Matching учитывает только те блоки, которые равны или длиннее 9cM.По мере того, как мы собираем больше данных, это число со временем, вероятно, изменится и станет ниже.

      • По нескольким причинам, включая жестко запрограммированный порог в 9 см, многие совпадения будут отображаться на индивидуальной странице совпадений, но не будут содержать значок матери или отца. Эти совпадения могут быть действительными, но они еще не были назначены на основе критериев поэтапного сопоставления семей на сегодняшний день.

    4. В среднем с нашими текущими формулами примерно 30-50% совпадений (если оба родителя или ни один из них не принадлежат к эндогамной популяции) связаны как минимум с одним связанным узлом родителя.Кроме того, мы наблюдаем от 10 до 20% совпадений, совмещенных по крайней мере с одним связанным узлом тетя / племянница или дядя / племянник с 1 st двоюродным братом.

    5. У нас есть планы на предстоящие обновления, так как это всего лишь первое в длинной череде улучшений, разработанных и запланированных на ближайшее будущее.

      • Благодаря нашему мягкому запуску этой последней функции количество пользователей оказалось больше, чем ожидалось. В настоящее время мы работаем как над скоростью, так и над дополнительными обновлениями, которые улучшат текущий опыт и помогут с будущими улучшениями и новыми функциями.Первое запланированное обновление ожидается в течение следующих шести недель. Более подробная информация о новых улучшениях системы Family Matching будет опубликована по мере приближения к запуску и уточнения всех новейших функций.

    Связанные темы:

    Что такое совпадение ДНК X в ДНК Семейного древа?

    Вы хотите знать, что означает совпадение X-ДНК на ДНК Семейного древа? В этом посте вы узнаете ответ, а также как выяснить, как ваше совпадение X-DNA связано с вами.

    совпадений X-DNA могут дать ключ к разгадке аспектов вашего генеалогического древа, о которых вы иначе могли бы не знать. Кроме того, уникальный образец наследования X-ДНК может дать вам подробную информацию о вашем родстве.

    Family Tree DNA - это отличная услуга по тестированию ДНК, и веб-сайт позволяет нам просматривать подробные сведения о нашей генетической связи с нашими совпадениями. Поначалу это может показаться сложным, но этот пост предоставит вам информацию, необходимую для понимания ваших совпадений X-DNA.

    Что означает совпадение ДНК по X на FTDNA?

    Если у вас есть совпадение X-ДНК на ДНК Семейного древа (FTDNA), это означает, что у вас и у вашего совпадения есть хотя бы один идентичный сегмент ДНК на вашей X-хромосоме.

    Ваша Х-хромосома - одна из ваших половых хромосом. Если вы женщина, у вас две X-хромосомы, а если вы мужчина, у вас есть X и Y-хромосомы.

    Другими словами, если у вас есть совпадение X-ДНК на FTDNA, у вас и у вашей пары одинаковый генетический материал на вашей половой хромсоме.

    Для мужчин значение совпадения по Х-хромосоме более очевидно. Мужчины не наследуют X-ДНК от своего отца, а это означает, что X-ДНК, общая с совпадением, должна была быть получена от их матери.

    Самки наследуют ДНК X как от матери, так и от отца. X-ДНК, которую они унаследовали от своего отца, пришла от их бабушки по отцовской линии, поскольку дедушка не передавал X-ДНК своей внучке.

    Х-ДНК, унаследованная самками от матери, произошла от полной Х-хромосомы, переданной от отца, а рекомбинированная Х-хромосома передается от матери.

    Как вы связаны с вашим совпадением X-ДНК на ДНК Семейного древа?

    Чтобы выяснить, как вы связаны со своими совпадениями X-ДНК, необходимо больше изучить способ передачи X-ДНК.

    Самцы и X-ДНК совпадают на генеалогическом древе ДНК

    Мы уже знаем, что самцы могут полностью исключить свою отцовскую сторону при поиске возможных связей. Другими словами, совпадение X-ДНК не могло произойти со стороны их отца.

    Мужчина может взглянуть на линии своей матери, чтобы выяснить, какое отношение он может иметь к своему совпадению по X-ДНК.Понимание модели наследования может помочь нам в дальнейшем исключить потенциальные связи мужчин с их совпадениями X-ДНК.

    Поскольку мать мужчины унаследовала X-ДНК от обоих родителей, мы не можем их устранить. Но мы знаем, что дедушка по отцовской линии не передавал ДНК своему внуку.

    Мне помогает нарисовать на бумаге простую семейную карту. Таким образом, я знаю, с какими линиями дерева может быть связано совпадение X-ДНК.

    В зависимости от того, насколько велик общий сегмент X-ДНК, мне, возможно, не придется возвращаться очень далеко назад в моем графике.Сузив несколько строк, я могу сравнить эти фамилии с генеалогическим деревом мужчины, совпадающим с X-ДНК.

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

    Самки и X-ДНК совпадают на FTDNA

    Поскольку женщины передают X-ДНК от обоих родителей, нам нелегко исключить 50% наших предков как возможных связей, как мы это делаем с мужчинами.

    Однако тот же базовый образец наследования справедлив и для женщин.Когда я пытаюсь визуализировать X-ДНК в своей голове, я немного сбиваюсь с толку.

    Прошу прощения за мой почерк ниже «куриной царапины», если хотите. Это тип рисунка, который я часто делаю (снова и снова), исследуя свои совпадения X-ДНК.

    Женщина-тестировщик ДНК унаследовала X-ДНК от обоих родителей, о чем свидетельствует значок (X) рядом с именем предка. Мы видим, что NO X-ДНК передалась от ее деда.

    Если это близкое совпадение X-DNA, мы, возможно, уже знаем, какие фамилии сравнивать.Это особенно полезно, если у вас есть доступ к информации о генеалогическом древе вашего совпадения ДНК, если это возможно.

    Мы можем пойти дальше в нашей таблице, чтобы исключить больше возможностей в поисках общего предка.

    Если мы нарисуем диаграмму, добавив еще одно поколение, мы увидим, что женщина могла унаследовать X-ДНК от:

    • Дедушка ее отца по материнской линии
    • Бабушка ее отца по материнской линии
    • Ее дедушка и бабушка по материнской линии
    • Бабушка и дедушка по отцовской линии ее матери
    • Бабушка и дедушка по материнской линии

    Если хотите, вы можете распечатать родословную со своего дерева наследование X-ДНК обратно, исключая потенциальные линии и фамилии.

    Затем сравните свое дерево с деревом совпадений X-DNA, чтобы найти общие фамилии. Общие фамилии могут указывать на ваше отношение к вашему совпадению с X-ДНК.

    Вы можете быть связаны с вашим совпадением X-DNA более чем одним способом

    Вы можете быть связаны с вашим совпадением X-DNA разными способами. Если у вас общая аутосомная ДНК с совпадающей ДНК, вы могли унаследовать ее от того же общего предка, который передал вам X-ДНК.

    В качестве альтернативы, вы могли быть связаны с совпадением ДНК двумя или более способами, то есть X-ДНК была передана от общего предка, отличного от того, который передал аутосомную ДНК.

    Эта проблема также возникает при совпадении аутосомной ДНК.

    Заключение

    Я надеюсь, что этот пост помог вам больше узнать о том, как понять ваши совпадения X-ДНК с ДНК Семейного древа и как выяснить, как они могут быть связаны.

    Если у вас есть какие-либо вопросы о том, что вы прочитали в этом посте, или если у вас есть дополнительные вопросы о совпадениях ДНК X на FTDNA, присоединяйтесь к нам в обсуждении ниже.

    Leave a Reply