سؤال

قررت أن أتبع النهج الوظيفي في إنشاء سلسلة أو أحرف عشوائية، حتى الآن توصلت إلى هذا، يجب أن يؤدي أداءً أفضل من الملاكمة ثم استخدام StringJoiner كجامع:

Random random = new Random();
String randomString = IntStream.concat(
        random.ints(8, 'a', 'z'),
        random.ints(8, 'A', 'Z')
)
        .collect(
                StringBuilder::new,
                (sb, i) -> sb.append((char)i),
                (sb1, sb2) -> sb1.append(sb2)
        ).toString();

أريد إنشاء دفق مكون من 16 حرفًا، بدءًا من a-z أو A-Z، والمشكلة التي أواجهها هي أنني لا أعرف كيفية الخلط بين كلا الدفقين.

وأنا أعلم أنني أستخدم IntStream.concat هنا، والذي سوف يربط كلا التدفقين ببساطة، فأنا أبحث عن أي مما يلي:

  • عامل ثابت مثل IntStream.concat الذي يقوم بالخلط عند دمج التدفقات.
  • مشغل تيار مثل sorted().

كلتا الطريقتين قابلتان للتطبيق في رأيي، لكنني مهتم بشكل خاص بكيفية جعل المشغل متشابهًا sorted().النقطة الأساسية هنا هي أن المشغل ذو الحالة لأنه يحتاج إلى رؤية التدفق بالكامل قبل أن يتمكن من العمل، هل هناك طريقة لإدخال عامل ذو حالة في تسلسل التدفق؟

حتى الآن، يبدو أن العمليات، باستثناء العمل المطلوب لخلطها، غير مناسبة للنهج الوظيفي في Java 8.

هل كانت مفيدة؟

المحلول

أنت تفكر ملتوية للغاية

Random random = new Random();
String randomString=random.ints(16, 0, 26*2).map(i->(i>=26? 'a'-26: 'A')+i)
  .collect(StringBuilder::new,
           StringBuilder::appendCodePoint, StringBuilder::append)
  .toString();

نظرًا لأن لديك بالفعل مصدرًا للقيم العشوائية، فلا داعي لاستدعاء وظيفة خلط ورق اللعب (والتي لن تعمل بشكل جيد مع تيارات).

لاحظ أنه يمكنك أيضًا تحديد الأحرف المسموح بها في ملف String بشكل صريح وتحديدها باستخدام:random.ints(16, 0, allowed.length()).map(allowed::charAt)

ينطبق نمط مماثل على الاختيار من الوصول العشوائي List.


تحديث:إذا كنت تريد الحصول على رمز يُظهر بوضوح طبيعة النطاقين للأحرف المسموح بها، فيمكنك دمجها Stream.concat النهج مع char حل الاختيار الموصوف أعلاه:

StringBuilder allowed=
  IntStream.concat(IntStream.rangeClosed('a', 'z'), IntStream.rangeClosed('A', 'Z'))
    .collect(StringBuilder::new,
             StringBuilder::appendCodePoint, StringBuilder::append);
String randomString=random.ints(16, 0, allowed.length()).map(allowed::charAt)
  .collect(StringBuilder::new,
           StringBuilder::appendCodePoint, StringBuilder::append)
  .toString();

(ملحوظة:أنا محل range مع rangeClosed والذي أظن أنه يطابق نواياك الأصلية بينما لا يفعل ماذا Random.ints(…, 'a', 'z') ستفعل).

نصائح أخرى

ربما لا يكون هذا أنيقًا كما كنت تأمل ولكنه يعمل:

final Random random = new Random();
String randomString = IntStream.concat(random.ints(8, 'a', 'z'+1), random.ints(8, 'A', 'Z'+1))
    .collect(StringBuilder::new, (sb, i) -> {
      int l = sb.length();
      if (l == 0) {
        sb.append((char) i);
      } else {
        int j = random.nextInt(l);
        char c = sb.charAt(j);
        sb.setCharAt(j, (char) i);
        sb.append(c);
      }
    }, (sb1, sb2) -> sb1.append(sb2)).toString();
System.out.println(randomString);

بدلا من ذلك يمكنك القيام بذلك:

final String randomString = random.ints(100, 'A', 'z' + 1)
        .filter(i -> i <= 'Z' || i >= 'a').limit(16)
        .collect(StringBuilder::new, (sb, i) -> sb.append((char) i), 
                StringBuilder::append).toString();
مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top