Stream<String> a = Stream.of("one", "three", "five");
Stream<String> b = Stream.of("two", "four", "six");
我要怎么做才能使输出显示如下?
// one
// two
// three
// four
// five
// six
我查看了concat
,但正如javadoc解释的那样,它只是一个接一个地追加,它不会交错/散布。
Stream<String> out = Stream.concat(a, b);
out.forEach(System.out::println);
创建一个元素所有为 第一流的元素,然后是所有元素 第二流。
错误地给予
// one
// three
// five
// two
// four
// six
如果我收集它们并对其进行迭代,可以这样做,但是希望有更多Java8-y,Streamy:-)
注意
我不想压缩流
“ zip”操作将从每个集合中获取一个元素并将其组合。
zip操作的结果如下:(不需要)
// onetwo
// threefour
// fivesix
答案 0 :(得分:11)
我会使用类似这样的东西:
public static <T> Stream<T> interleave(Stream<T> a, Stream<T> b) {
Spliterator<T> spA = a.spliterator(), spB = b.spliterator();
long s = spA.estimateSize() + spB.estimateSize();
if(s < 0) s = Long.MAX_VALUE;
int ch = spA.characteristics() & spB.characteristics()
& (Spliterator.NONNULL|Spliterator.SIZED);
ch |= Spliterator.ORDERED;
return StreamSupport.stream(new Spliterators.AbstractSpliterator<T>(s, ch) {
Spliterator<T> sp1 = spA, sp2 = spB;
@Override
public boolean tryAdvance(Consumer<? super T> action) {
Spliterator<T> sp = sp1;
if(sp.tryAdvance(action)) {
sp1 = sp2;
sp2 = sp;
return true;
}
return sp2.tryAdvance(action);
}
}, false);
}
它尽可能保留输入流的特征,从而可以进行某些优化(例如,count()
和toArray()
)。此外,即使输入流可能无序,它也会添加ORDERED
来反映交织。
当一个流中的元素多于另一个时,其余元素将显示在末尾。
答案 1 :(得分:2)
比Holger笨拙的解决方案,但可能会满足您的要求:
<?php
class SMPP{
var $debug = true;
//SMPP bind parameters
//var $system_type="WWW";
var $interface_version=0x34;
var $addr_ton=0;
var $addr_npi=0;
var $address_range="";
//ESME transmitter parameters
var $sms_service_type="";
var $sms_source_addr_ton=0;
var $sms_source_addr_npi=0;
var $sms_dest_addr_ton=0;
var $sms_dest_addr_npi=0;
var $sms_esm_class=0;
var $sms_protocol_id=0;
var $sms_priority_flag=0;
var $sms_schedule_delivery_time="";
var $sms_validity_period="";
var $sms_registered_delivery_flag=0;
var $sms_replace_if_present_flag=0;
var $sms_data_coding=0;
var $sms_sm_default_msg_id=0;
/**
* Constructs the smpp class
* @param $host - SMSC host name or host IP
* @param $port - SMSC port
*/
function SMPP($host, $port=5016){
//internal parameters
$this->sequence_number=1;
$this->debug=false;
$this->pdu_queue=array();
$this->host=$host;
$this->port=$port;
$this->state="closed";
//open the socket
$this->socket=fsockopen($this->host, $this->port, $errno, $errstr, 30);
if($this->socket)$this->state="open";
}
/**
* Binds the receiver. One object can be bound only as receiver or only as trancmitter.
* @param $login - ESME system_id
* @param $port - ESME password
* @return true when bind was successful
*/
function bindTransceiver($login, $pass){
if($this->state!="open")return false;
if($this->debug){
echo "Binding transciever...\n\n";
}
$status=$this->_bind($login, $pass, 0x00000009);
if($this->debug){
echo "Binding status : $status\n\n";
}
if($status===0)$this->state="bind_trx";
return ($status===0);
}
/**
* Binds the receiver. One object can be bound only as receiver or only as trancmitter.
* @param $login - ESME system_id
* @param $port - ESME password
* @return true when bind was successful
*/
function bindReceiver($login, $pass){
if($this->state!="open")return false;
if($this->debug){
echo "Binding receiver...\n\n";
}
$status=$this->_bind($login, $pass, 0x00000001);
if($this->debug){
echo "Binding status : $status\n\n";
}
if($status===0)$this->state="bind_rx";
return ($status===0);
}
/**
* Binds the transmitter. One object can be bound only as receiver or only as trancmitter.
* @param $login - ESME system_id
* @param $port - ESME password
* @return true when bind was successful
*/
function bindTransmitter($login, $pass){
if($this->state!="open")return false;
if($this->debug){
echo "Binding transmitter...\n\n";
}
$status=$this->_bind($login, $pass, 0x00000002);
if($this->debug){
echo "Binding status : $status\n\n";
}
if($status===0)$this->state="bind_tx";
return ($status===0);
}
/**
* Closes the session on the SMSC server.
*/
function close(){
if($this->state=="closed")return;
if($this->debug){
echo "Unbinding...\n\n";
}
$status=$this->sendCommand(0x00000006,"");
if($this->debug){
echo "Unbind status : $status\n\n";
}
fclose($this->socket);
$this->state="closed";
}
/**
* Read USSD response from SMSC.
* @return
*/
function readResponse () {
if($this->state!="bind_trx")return false;
//set command id
$command_id = 0x00000005;
}
/**
* Read one SMS from SMSC. Can be executed only after bindReceiver() call.
* This method bloks. Method returns on socket timeout or enquire_link signal from SMSC.
* @return sms associative array or false when reading failed or no more sms.
*/
function readSMS(){
if($this->state!="bind_rx")return false;
//stream_set_timeout($this->socket, 10);
$command_id=0x00000005;
//check the queue
for($i=0;$i<count($this->pdu_queue);$i++){
$pdu=$this->pdu_queue[$i];
if($pdu['id']==$command_id){
//remove responce
array_splice($this->pdu_queue, $i, 1);
return parseSMS($pdu);
}
}
//read pdu
do{
if($this->debug){
echo "read sms...\n\n";
}
$pdu=$this->readPDU();
//check for enquire link command
if($pdu['id']==0x00000015){
$this->sendPDU(0x80000015, "", $pdu['sn']);
return false;
}
array_push($this->pdu_queue, $pdu);
}while($pdu && $pdu['id']!=$command_id);
if($pdu){
array_pop($this->pdu_queue);
return $this->parseSMS($pdu);
}
return false;
}
/**
* Read one SMS from SMSC. Can be executed only after bindTransmitter() call.
* @return true on succesfull send, false if error encountered
*/
function sendSMS($from, $to, $message){
if (strlen($from)>20 || strlen($to)>20)return false;
if($this->state!="bind_tx")return false;
$short_message = $message;
//*
// echo "test is just test ".$from;
if(strlen($message) > 160){
$length = 153;
$max = 153;
$msgs = array();
array_push($msgs, substr($message, 0, $max));
//echo $message." just me";
while(true){
if(strlen($message) - $length > $max){
array_push($msgs, substr($message, $length, $max));
$length = $length + $max;
//echo "always here";
// msgs.add(message.substring(tempCount, max));
// tempCount += max;
}else{
//echo "always here still";
array_push($msgs, substr($message, $length));
//$msgs.add(message.substring(tempCount));
break;
}
}
//echo count($msgs)." count\n";
if(count($msgs) > 0){
for($i = 0; $i < count($msgs); $i++){
$short_message = $msgs[$i];
//*
// echo "\n".$short_message.": ".$i ;
$pdu = pack('a1cca'.(strlen($from)+1).'cca'.(strlen($to)+1).'ccca1a1ccccca'.(strlen($short_message)+1),
$this->sms_service_type,
$this->sms_source_addr_ton,
$this->sms_source_addr_npi,
$from,//source_addr
$this->sms_dest_addr_ton,
$this->sms_dest_addr_npi,
$to,//destination_addr
$this->sms_esm_class,
$this->sms_protocol_id,
$this->sms_priority_flag,
$this->sms_schedule_delivery_time,
$this->sms_validity_period,
$this->sms_registered_delivery_flag,
$this->sms_replace_if_present_flag,
$this->sms_data_coding,
$this->sms_sm_default_msg_id,
strlen($short_message),//sm_length
$short_message//short_message
);
$status=$this->sendCommand(0x00000004,$pdu);
// echo "\n".$status."final\n";
}
// return $status === 0;
}
}else{
$short_message = $message;
//*
$pdu = pack('a1cca'.(strlen($from)+1).'cca'.(strlen($to)+1).'ccca1a1ccccca'.(strlen($message)+1),
$this->sms_service_type,
$this->sms_source_addr_ton,
$this->sms_source_addr_npi,
$from,//source_addr
$this->sms_dest_addr_ton,
$this->sms_dest_addr_npi,
$to,//destination_addr
$this->sms_esm_class,
$this->sms_protocol_id,
$this->sms_priority_flag,
$this->sms_schedule_delivery_time,
$this->sms_validity_period,
$this->sms_registered_delivery_flag,
$this->sms_replace_if_present_flag,
$this->sms_data_coding,
$this->sms_sm_default_msg_id,
strlen($message),//sm_length
$message//short_message
);
$status=$this->sendCommand(0x00000004,$pdu);
}
//*/
// return $status;
//echo $status."This is a test";
return ($status == 0);
}
////////////////private functions///////////////
/**
* @private function
* Binds the socket and opens the session on SMSC
* @param $login - ESME system_id
* @param $port - ESME password
* @return bind status or false on error
*/
function _bind($login, $pass, $command_id){
//make PDU
$pdu = pack(
'a'.(strlen($login)+1).
'a'.(strlen($pass)+1).
'a'.(strlen($this->system_type)+1).
'CCCa'.(strlen($this->address_range)+1),
$login, $pass, $this->system_type,
$this->interface_version, $this->addr_ton,
$this->addr_npi, $this->address_range);
$status=$this->sendCommand($command_id,$pdu);
return $status;
}
/**
* @private function
* Parse deliver PDU from SMSC.
* @param $pdu - deliver PDU from SMSC.
* @return parsed PDU as array.
*/
function parseSMS($pdu){
//check command id
if($pdu['id']!=0x00000005)return false;
//unpack PDU
$ar=unpack("C*",$pdu['body']);
$sms=array('service_type'=>$this->getString($ar,6),
'source_addr_ton'=>array_shift($ar),
'source_addr_npi'=>array_shift($ar),
'source_addr'=>$this->getString($ar,21),
'dest_addr_ton'=>array_shift($ar),
'dest_addr_npi'=>array_shift($ar),
'destination_addr'=>$this->getString($ar,21),
'esm_class'=>array_shift($ar),
'protocol_id'=>array_shift($ar),
'priority_flag'=>array_shift($ar),
'schedule_delivery_time'=>array_shift($ar),
'validity_period'=>array_shift($ar),
'registered_delivery'=>array_shift($ar),
'replace_if_present_flag'=>array_shift($ar),
'data_coding'=>array_shift($ar),
'sm_default_msg_id'=>array_shift($ar),
'sm_length'=>array_shift($ar),
'short_message'=>$this->getString($ar,255)
);
if($this->debug){
echo "Delivered sms:\n";
print_r($sms);
echo "\n";
}
//send responce of recieving sms
$this->sendPDU(0x80000005, "\0", $pdu['sn']);
return $sms;
}
/**
* @private function
* Sends the PDU command to the SMSC and waits for responce.
* @param $command_id - command ID
* @param $pdu - PDU body
* @return PDU status or false on error
*/
function sendCommand($command_id, $pdu){
if($this->state=="closed")return false;
$this->sendPDU($command_id, $pdu, $this->sequence_number);
$status=$this->readPDU_resp($this->sequence_number, $command_id);
$this->sequence_number=$this->sequence_number+1;
return $status;
}
/**
* @private function
* Prepares and sends PDU to SMSC.
* @param $command_id - command ID
* @param $pdu - PDU body
* @param $seq_number - PDU sequence number
*/
function sendPDU($command_id, $pdu, $seq_number){
$length=strlen($pdu) + 16;
$header=pack("NNNN", $length, $command_id, 0, $seq_number);
if($this->debug){
echo "Send PDU : $length bytes\n";
$this->printHex($header.$pdu);
echo "command_id : ".$command_id."\n";
echo "sequence number : $seq_number\n\n";
}
fwrite($this->socket, $header.$pdu, $length);
}
/**
* @private function
* Waits for SMSC responce on specific PDU.
* @param $seq_number - PDU sequence number
* @param $command_id - PDU command ID
* @return PDU status or false on error
*/
function readPDU_resp($seq_number, $command_id){
//create responce id
$command_id=$command_id|0x80000000;
//check queue
for($i=0;$i<count($this->pdu_queue);$i++){
$pdu=$this->pdu_queue[$i];
if($pdu['sn']==$seq_number && $pdu['id']==$command_id){
//remove responce
array_splice($this->pdu_queue, $i, 1);
return $pdu['status'];
}
}
//read pdu
do{
$pdu=$this->readPDU();
if($pdu)array_push($this->pdu_queue, $pdu);
}while($pdu && ($pdu['sn']!=$seq_number || $pdu['id']!=$command_id));
//remove responce from queue
if($pdu){
array_pop($this->pdu_queue);
return $pdu['status'];
}
return false;
}
/**
* @private function
* Reads incoming PDU from SMSC.
* @return readed PDU or false on error.
*/
function readPDU(){
//read PDU length
$tmp=fread($this->socket, 4);
if(!$tmp)return false;
extract(unpack("Nlength", $tmp));
//read PDU headers
$tmp2=fread($this->socket, 12);
if(!$tmp2)return false;
extract(unpack("Ncommand_id/Ncommand_status/Nsequence_number", $tmp2));
//read PDU body
if($length-16>0){
$body=fread($this->socket, $length-16);
if(!$body)return false;
}else{
$body="";
}
if($this->debug){
echo "Read PDU : $length bytes\n";
$this->printHex($tmp.$tmp2.$body);
echo "body len : " . strlen($body) . "\n";
echo "Command id : $command_id\n";
echo "Command status : $command_status\n";
echo "sequence number : $sequence_number\n\n";
}
$pdu=array(
'id'=>$command_id,
'status'=>$command_status,
'sn'=>$sequence_number,
'body'=>$body);
return $pdu;
}
/**
* @private function
* Reads C style zero padded string from the char array.
* @param $ar - input array
* @param $maxlen - maximum length to read.
* @return readed string.
*/
function getString(&$ar, $maxlen=255){
$s="";
$i=0;
do{
$c=array_shift($ar);
if($c!=0)$s.=chr($c);
$i++;
}while($i<$maxlen && $c!=0);
return $s;
}
/**
* @private function
* Prints the binary string as hex bytes.
* @param $maxlen - maximum length to read.
*/
function printHex($pdu){
$ar=unpack("C*",$pdu);
foreach($ar as $v){
$s=dechex($v);
if(strlen($s)<2)$s="0$s";
print "$s ";
}
print "\n";
}
}
?>
答案 2 :(得分:2)
从问题注释中可以看到,我使用zip进行了尝试:
Stream<String> a = Stream.of("one", "three", "five");
Stream<String> b = Stream.of("two", "four", "six");
Stream<String> out = interleave(a, b);
public static <T> Stream<T> interleave(Stream<T> streamA, Stream<T> streamB) {
return zip(streamA, streamB, (o1, o2) -> Stream.of(o1, o2)).flatMap(s -> s);
}
/**
* https://stackoverflow.com/questions/17640754/zipping-streams-using-jdk8-with-lambda-java-util-stream-streams-zip
**/
private static <A, B, C> Stream<C> zip(Stream<A> streamA, Stream<B> streamB, BiFunction<A, B, C> zipper) {
final Iterator<A> iteratorA = streamA.iterator();
final Iterator<B> iteratorB = streamB.iterator();
final Iterator<C> iteratorC = new Iterator<C>() {
@Override
public boolean hasNext() {
return iteratorA.hasNext() && iteratorB.hasNext();
}
@Override
public C next() {
return zipper.apply(iteratorA.next(), iteratorB.next());
}
};
final boolean parallel = streamA.isParallel() || streamB.isParallel();
return iteratorToFiniteStream(iteratorC, parallel);
}
private static <T> Stream<T> iteratorToFiniteStream(Iterator<T> iterator, boolean parallel) {
final Iterable<T> iterable = () -> iterator;
return StreamSupport.stream(iterable.spliterator(), parallel);
}
答案 3 :(得分:1)
这可能不是是一个很好的答案,因为
(1)它会收集到地图,我想您不想这样做,
(2)它不是完全无状态的,因为它使用AtomicIntegers。
之所以添加它,是因为
(1)可读且
(2)社区可以从中获得一个想法并尝试对其进行改进。
Stream<String> a = Stream.of("one", "three", "five");
Stream<String> b = Stream.of("two", "four", "six");
AtomicInteger i = new AtomicInteger(0);
AtomicInteger j = new AtomicInteger(1);
Stream.of(a.collect(Collectors.toMap(o -> i.addAndGet(2), Function.identity())),
b.collect(Collectors.toMap(o -> j.addAndGet(2), Function.identity())))
.flatMap(m -> m.entrySet().stream())
.sorted(Comparator.comparing(Map.Entry::getKey))
.forEach(e -> System.out.println(e.getValue())); // or collect
输出
one
two
three
four
five
six
@Holger的编辑
Stream.concat(a.map(o -> new AbstractMap.SimpleEntry<>(i.addAndGet(2), o)),
b.map(o -> new AbstractMap.SimpleEntry<>(j.addAndGet(2), o)))
.sorted(Map.Entry.comparingByKey())
.forEach(e -> System.out.println(e.getValue())); // or collect
答案 4 :(得分:1)
使用Iterator
final Iterator<String> iterA = a.iterator();
final Iterator<String> iterB = b.iterator();
final Iterator<String> iter = new Iterator<String>() {
private final AtomicInteger idx = new AtomicInteger();
@Override
public boolean hasNext() {
return iterA.hasNext() || iterB.hasNext();
}
@Override
public String next() {
return idx.getAndIncrement() % 2 == 0 && iterA.hasNext() ? iterA.next() : iterB.next();
}
};
// Create target Stream with StreamEx from: https://github.com/amaembo/streamex
StreamEx.of(iter).forEach(System.out::println);
// Or Streams from Google Guava
Streams.stream(iter).forEach(System.out::println);
或者仅由我提供的ASLR中的解决方案:
AtomicInteger idx = new AtomicInteger();
StreamEx.merge(a, b, (s1, s2) -> idx.getAndIncrement() % 2 == 0 ? Nth.FIRST : Nth.SECOND).forEach(Fn.println());
答案 5 :(得分:0)
使用番石榴的Streams.zip和Stream.flatMap
:
Stream<String> interleaved = Streams
.zip(a, b, (x, y) -> Stream.of(x, y))
.flatMap(Function.identity());
interleaved.forEach(System.out::println);
打印:
one
two
three
four
five
six