यदि आप किसी मेमोरी डेटा संरचना, जैसे किसी सरणी या सूची पर काम करने के इच्छुक हैं, तो इसे केवल कुछ चरणों में मानक जावा 8 में करना संभव है। यह सरणी प्रोग्रामिंग तकनीकों का उपयोग करके किया जा सकता है जैसे कि मेरे answer to this question में सचित्र। Flown's answer to this question में उपयोग की जाने वाली कुछ चालाक सशर्तियों का उपयोग किनारे के मामलों को एक साफ तरीके से ख्याल रखता है।
मुख्य अंतर्दृष्टि यह जानना है कि एक नया सेगमेंट (या समूह) प्रत्येक बिंदु पर शुरू होता है जहां वांछित भविष्यवाणी नहीं मिली है। यही है, एक नया सेगमेंट शुरू होता है जहां seq[i-1] + 1 != seq[i]
है। के इनपुट पर एक IntStream
चलाते हैं और इस संपत्ति के लिए अनुक्रमणिका को फ़िल्टर और कुछ सरणी x
में परिणाम की दुकान:
int[] seq = { 1, 2, 3, -1, -1, 1, 2, 1, 2 };
int[] x = IntStream.range(1, seq.length)
.filter(i -> seq[i-1] + 1 != seq[i])
.toArray();
में जिसके परिणामस्वरूप
[3, 4, 5, 7]
यह केवल हमें आंतरिक देता है की सीमाओं खंडों। सेगमेंट के प्रारंभ और सिरों को पाने के लिए, हमें पहले सेगमेंट की शुरुआत और अंतिम सेगमेंट के अंत में काम करने की जरूरत है। हम सूचकांक सीमा समायोजित और फिल्टर करने के लिए कुछ सशर्त जोड़ें:
int[] x = IntStream.rangeClosed(0, seq.length)
.filter(i -> i == 0 || i == seq.length ||
seq[i-1] + 1 != seq[i])
.toArray();
[0, 3, 4, 5, 7, 9]
अब अनुक्रमित के हर आसन्न जोड़ी मूल सरणी के एक subrange है। हम उन subranges को निकालने के लिए, वांछित परिणाम दे रही है एक और धारा का उपयोग कर सकते हैं:
int[][] result =
IntStream.range(0, x.length - 1)
.mapToObj(i -> Arrays.copyOfRange(seq, x[i], x[i+1]))
.toArray(int[][]::new);
[[1, 2, 3], [-1], [-1], [1, 2], [1, 2]]
यह एक समारोह है कि अपने आप में एक "अगला" समारोह है कि क्षेत्र में अगले मूल्य की गणना करता है लेता में निकाला जा सकता है। यही है, किसी भी तत्व के लिए, यदि उसके दाहिने तत्व का तत्व अगले-फ़ंक्शन के परिणाम से मेल खाता है, तो तत्व एक ही सेगमेंट में हैं; अन्यथा यह एक सेगमेंट सीमा है।कोड यह रहा:
int[][] segments(int[] seq, IntUnaryOperator next) {
int[] x = IntStream.rangeClosed(0, seq.length)
.filter(i -> i == 0 || i == seq.length ||
next.applyAsInt(seq[i-1]) != seq[i])
.toArray();
return IntStream.range(0, x.length - 1)
.mapToObj(i -> Arrays.copyOfRange(seq, x[i], x[i+1]))
.toArray(int[][]::new);
}
आप इसे इस तरह फोन चाहते हैं:
int[] seq = { 1, 2, 3, -1, -1, 1, 2, 1, 2 };
System.out.println(Arrays.deepToString(segments(seq, i -> i + 1)));
[[1, 2, 3], [-1], [-1], [1, 2], [1, 2]]
अगली समारोह बदलने की अनुमति देता है एक अलग तरह से खंडों बंटवारे। उदाहरण के लिए, बराबर मूल्यों के खंडों में एक सरणी विभाजित करने के लिए, यदि आप ऐसा करते हैं:
int[] seq = { 2, 2, 1, 3, 3, 1, 1, 1, 4, 4, 4 };
System.out.println(Arrays.deepToString(segments(seq, i -> i)));
[[2, 2], [1], [3, 3], [1, 1, 1], [4, 4, 4]]
इस तरह की एक अगली समारोह का उपयोग कर के साथ कठिनाई यह है कि एक खंड से संबंधित मूल्यों के लिए शर्त सीमित है। यह अच्छी तरह से एक भविष्यवाणी प्रदान करेगा जो आसन्न मूल्यों की तुलना करता है ताकि वे जांच कर सकें कि वे एक ही सेगमेंट में हैं या नहीं। हम जानते हैं कि एक BiPredicate<Integer, Integer>
का उपयोग कर अगर हम मुक्केबाजी की लागत का भुगतान करने को तैयार हैं कर सकते हैं:
int[][] segments(int[] input, BiPredicate<Integer, Integer> pred) {
int[] x = IntStream.rangeClosed(0, input.length)
.filter(i -> i == 0 || i == input.length ||
!pred.test(input[i-1], input[i]))
.toArray();
return IntStream.range(0, x.length - 1)
.mapToObj(i -> Arrays.copyOfRange(input, x[i], x[i+1]))
.toArray(int[][]::new);
}
यह एक अलग कसौटी का उपयोग कर, उदाहरण के लिए, होगा- क्षेत्रों में वृद्धि सभा क्षेत्रों की अनुमति देता है:
int[] seq = { 3, 1, 4, 1, 5, 9, 2, 6, 5, 3 };
System.out.println(Arrays.deepToString(segments(seq, (a, b) -> b > a)));
[[3], [1, 4], [1, 5, 9], [2, 6], [5], [3]]
यह दो int
मानों पर एक आदिम द्वि-भविष्यवाणी का उपयोग करने के लिए विशेषीकृत किया जा सकता है, या इसे किसी भी प्रकार के इनपुट के किसी भी प्रकार के BiPredicate
का उपयोग करने की अनुमति देने के लिए सामान्यीकृत किया जा सकता है।
आउटपुट इस तरह दिखने चाहिए: '[[1,2,3], [-1], [-1,1,2], [1,2]]'? – Flown
@ फ्लाउन नहीं क्योंकि '1! = Next.apply (-1)' – Tunaki
आह ठीक है 'अगला' एक अनुमान है। – Flown