выбор на основе процентного веса

Ссылаясь на сообщение Рохо на https://stackoverflow.com/a/15032476/3627676

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

@echo off

set "hello=Hello world!"
set "lorem=Lorem ipsum dolor sit amet, consectetur adipiscing elit."

call :heredoc HTML & goto :HTML

!hello!

Variables in heredoc should be surrounded by the exclamation mark (^!).

!lorem!

Exclamation mark (^!) and caret (^^) MUST be escaped with a caret (^^).

:HTML goto :EOF :: https://stackoverflow.com/a/15032476/3627676 :heredoc LABEL setlocal enabledelayedexpansion set go= for /f "delims=" %%A in ( ' findstr /n "^" "%~f0" ' ) do ( set "line=%%A" set "line=!line:*:=!" if defined go ( if /i "!line!" == "!go!" goto :EOF echo:!line! ) else ( rem delims are ( ) > & | TAB , ; = SPACE for /f "tokens=1-3 delims=()>&| ,;= " %%i in ( "!line!" ) do ( if /i "%%i %%j %%k" == "call :heredoc %1" ( set "go=%%k" if not "!go:~0,1!" == ":" set "go=:!go!" ) ) ) ) goto :EOF

Что я предлагаю этим кодом? Давайте рассмотрим.

Код Рохо очень строг:

  • не допускает использование более одного пробела в строке между call и :heredoc
  • call :heredoc привязан к краю строки (без пробелов в начале строки)
  • перенаправление в файл разрешено где-то внутри строки (не очень полезно) -

Вещи, которые я предлагаю:

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

Обновление 1 : улучшения в проверке и выполнении начала heredoc:

  • важная команда только call :heredoc LABEL или call :heredoc :LABEL. Таким образом, после распечатки содержимого heredoc можно перейти к другой метке, концу сценария или запустить exit /b.
  • удалены неиспользуемые и ненужные команды goto: next2

Обновление 2 :

  • Разделителями для внутреннего for являются ( ) > & | TAB , ; = SPACE
  • Переключатель /I добавлен в if

Обновление 3 :

По следующей ссылке вы можете найти полную версию автономного скрипта (встраивание в ваши скрипты доступно) https://github.com /ildar-shaimordanov/tea-set/blob/master/bin/heredoc.bat

27
задан Corey Goldberg 7 September 2010 в 02:52
поделиться

2 ответа

У меня есть собственное решение для этого:

public class Randomizator3000 
{    
public class Item<T>
{
    public T value;
    public float weight;

    public static float GetTotalWeight<T>(Item<T>[] p_itens)
    {
        float __toReturn = 0;
        foreach(var item in p_itens)
        {
            __toReturn += item.weight;
        }

        return __toReturn;
    }
}

private static System.Random _randHolder;
private static System.Random _random
{
    get 
    {
        if(_randHolder == null)
            _randHolder = new System.Random();

        return _randHolder;
    }
}

public static T PickOne<T>(Item<T>[] p_itens)
{   
    if(p_itens == null || p_itens.Length == 0)
    {
        return default(T);
    }

    float __randomizedValue = (float)_random.NextDouble() * (Item<T>.GetTotalWeight(p_itens));
    float __adding = 0;
    for(int i = 0; i < p_itens.Length; i ++)
    {
        float __cacheValue = p_itens[i].weight + __adding;
        if(__randomizedValue <= __cacheValue)
        {
            return p_itens[i].value;
        }

        __adding = __cacheValue;
    }

    return p_itens[p_itens.Length - 1].value;

}
}

И его использование должно быть примерно таким (вот в Unity3d)

using UnityEngine;
using System.Collections;

public class teste : MonoBehaviour 
{
Randomizator3000.Item<string>[] lista;

void Start()
{
    lista = new Randomizator3000.Item<string>[10];
    lista[0] = new Randomizator3000.Item<string>();
    lista[0].weight = 10;
    lista[0].value = "a";

    lista[1] = new Randomizator3000.Item<string>();
    lista[1].weight = 10;
    lista[1].value = "b";

    lista[2] = new Randomizator3000.Item<string>();
    lista[2].weight = 10;
    lista[2].value = "c";

    lista[3] = new Randomizator3000.Item<string>();
    lista[3].weight = 10;
    lista[3].value = "d";

    lista[4] = new Randomizator3000.Item<string>();
    lista[4].weight = 10;
    lista[4].value = "e";

    lista[5] = new Randomizator3000.Item<string>();
    lista[5].weight = 10;
    lista[5].value = "f";

    lista[6] = new Randomizator3000.Item<string>();
    lista[6].weight = 10;
    lista[6].value = "g";

    lista[7] = new Randomizator3000.Item<string>();
    lista[7].weight = 10;
    lista[7].value = "h";

    lista[8] = new Randomizator3000.Item<string>();
    lista[8].weight = 10;
    lista[8].value = "i";

    lista[9] = new Randomizator3000.Item<string>();
    lista[9].weight = 10;
    lista[9].value = "j";
}


void Update () 
{
    Debug.Log(Randomizator3000.PickOne<string>(lista));
}
}

В этом примере каждое значение имеет Вероятность 10% будет отображаться как отладка = 3

1
ответ дан 28 November 2019 в 04:32
поделиться

Кнут ссылается на псевдонимы Уокера. Поиск по этому, я нахожу http://code.activestate.com/recipes/576564-walkers-alias-method-for-random-objects-with-diffe/ и http: // prxq.wordpress.com/2006/04/17/the-alias-method/. Это дает точные вероятности, требуемые в постоянном времени для числа, сгенерированного с линейным временем для настройки (любопытно, что n log n время для настройки, если вы используете точно метод, описанный Кнутом, который делает подготовительную сортировку, которую вы можете избежать).

8
ответ дан 28 November 2019 в 04:32
поделиться
Другие вопросы по тегам:

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