Реализация этого как генератора делает его довольно приятным для работы. Обратите внимание: эта реализация отличается от той, которая требует, чтобы весь входной массив сначала перетасовался.
Эта функция
blockquote>sample
работает лениво, предоставляя вам 1 случайный элемент за итерацию доN
предметов, которые вы запрашиваете. Это хорошо, потому что, если вам просто нужно 3 элемента из списка 1000, сначала вам не нужно касаться всех 1000 элементов.
// sample :: Integer -> [a] -> [a] const sample = n => function* (xs) { let ys = xs.slice(0); let len = xs.length; while (n > 0 && len > 0) { let i = (Math.random() * len) >> 0; yield ys.splice(i,1)[0]; n--; len--; } } // example inputs let items = ['a', 'b', 'c', 'd', 'e', 'f', 'g']; let numbers = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]; // get 3 random items for (let i of sample(3) (items)) console.log(i); // f g c // partial application const lotto = sample(3); for (let i of lotto(numbers)) console.log(i); // 3 8 7 // shuffle an array const shuffle = xs => Array.from(sample (Infinity) (xs)) console.log(shuffle(items)) // [b c g f d e a]
Я решил реализовать
sample
способом, который не мутирует входной массив, но вы можете легко утверждать, что мутирующая реализация благоприятна.Например,
shuffle
функция может захотеть изменить исходный массив ввода. Или вы можете попробовать с одного и того же входа в разное время, каждый раз обновляя вход.
// sample :: Integer -> [a] -> [a] const sample = n => function* (xs) { let len = xs.length; while (n > 0 && len > 0) { let i = (Math.random() * len) >> 0; yield xs.splice(i,1)[0]; n--; len--; } } // deal :: [Card] -> [Card] const deal = xs => Array.from(sample (2) (xs)); // setup a deck of cards (13 in this case) // cards :: [Card] let cards = 'A234567890JQK'.split(''); // deal 6 players 2 cards each // players :: [[Card]] let players = Array.from(Array(6), $=> deal(cards)) console.log(players); // [K, J], [6, 0], [2, 8], [Q, 7], [5, 4], [9, A] // `cards` has been mutated. only 1 card remains in the deck console.log(cards); // [3]
sample
больше не чистая функция из-за входной мутации массива, но в определенных обстоятельствах (продемонстрировано выше) это может иметь больше смысла.Еще одна причина, по которой я выбрал генератор вместо функции, которая просто возвращает массив, потому что вы можете продолжить выборку до определенного условия.
Возможно, я хочу, чтобы первое простое число из списка из 1 000 000 случайных чисел.
- «Сколько должен ли я пробовать? » - вам не нужно указывать
- « Должен ли я сначала найти все простые числа, а затем выбрать случайное число? » - Нет.
Поскольку мы работаем с генератором, эта задача тривиальна
const randomPrimeNumber = listOfNumbers => { for (let x of sample(Infinity) (listOfNumbers)) { if (isPrime(x)) return x; } return NaN; }
Это будет непрерывно отображать 1 случайное число за раз,
x
, проверьте, является ли он простым, а затем возвратитеx
, если это так. Если список чисел исчерпан до того, как найдено штрих, возвращаетсяNaN
.Примечание:
Этот ответ был первоначально разделен по другому вопросу, который был закрыт как дубликат этого. Поскольку он сильно отличается от других предлагаемых здесь решений, я решил поделиться им и здесь
Служба, которую я вызывал (в данном случае Jira Cloud API от Atlassian), поддерживает как базовую, так и OAuth-аутентификацию. Я пытался использовать HTTP Basic, но он отправляет вызов аутентификации для OAuth.
Начиная с текущего JDK 11, HttpClient не отправляет базовые учетные данные, пока их не вызовут с помощью заголовка WWW-Authenticate с сервера. Кроме того, единственный тип вызова, который он понимает, - это обычная проверка подлинности. Соответствующий код JDK находится здесь (в комплекте с TODO для поддержки не только базовой аутентификации), если вы хотите взглянуть.
Тем временем я решил обойти API аутентификации HttpClient, а также сам создать и отправить заголовок Basic Authorization:
public static void main(String[] args) {
var client = HttpClient.newBuilder()
.version(HttpClient.Version.HTTP_1_1)
.build();
var request = HttpRequest.newBuilder()
.uri(new URI("https://service-that-needs-auth.example/"))
.header("Authorization", basicAuth("username", "password"))
.build();
client.sendAsync(request, HttpResponse.BodyHandlers.ofString())
.thenApply(HttpResponse::body)
.thenAccept(System.out::println)
.join();
}
private static String basicAuth(String username, String password) {
return "Basic " + Base64.getEncoder().encodeToString((username + ":" + password).getBytes());
}