2010-02-16 4 views
20

In Javascript, wie die Reihenfolge der Zahlen in einem Array in den Zahlenbereich zu konvertieren?Wie konvertiert man die Reihenfolge der Zahlen in einem Array in den Zahlenbereich

z. [2,3,4,5,10,18,19,20] to [2-5,10,18-20]

+0

Wie bestimmen Sie, wo ein Bereich beginnt und endet? – Sampson

+5

@gokul: Ich habe Ihre Frage bearbeitet (Beispiel aus Titel, formatierter Text entfernt). Sie können Menschen motivieren, zu helfen, indem Sie Ihre Frage richtig formatieren. –

Antwort

1

Wenn Sie nur eine Zeichenfolge möchten, die einen Bereich darstellt, dann finden Sie den Mittelpunkt Ihrer Sequenz, und das wird Ihr mittlerer Wert (10 in Ihrem Beispiel). Sie würden dann das erste Element in der Sequenz und das Element, das unmittelbar vor Ihrem Mittelpunkt liegt, erfassen und Ihre erste Sequenzrepräsentation erstellen. Sie würden genauso vorgehen, um den letzten Gegenstand und den Gegenstand, der unmittelbar auf Ihren Mittelpunkt folgt, zu erhalten und Ihre Darstellung der letzten Folge zu erstellen.

// Provide initial sequence 
var sequence = [1,2,3,4,5,6,7,8,9,10]; 
// Find midpoint 
var midpoint = Math.ceil(sequence.length/2); 
// Build first sequence from midpoint 
var firstSequence = sequence[0] + "-" + sequence[midpoint-2]; 
// Build second sequence from midpoint 
var lastSequence = sequence[midpoint] + "-" + sequence[sequence.length-1]; 
// Place all new in array 
var newArray = [firstSequence,midpoint,lastSequence]; 

alert(newArray.join(",")); // 1-4,5,6-10 

Demo Online: http://jsbin.com/uvahi/edit

+3

Wäre die Ausgabe nicht 1-10, da die Zahlen 1-10 nacheinander erscheinen und keine fehlen? –

0

Sie könnten die Zahlen iterieren und sehen, ob die nächste Nummer 1 größer als die aktuelle Zahl. So habe ein:

struct range { 
    int start; 
    int end; 
} range; 

wo wenn array[i+1] == array[i]+1; (wo i die aktuell beobachtete Anzahl) dann range.end = array[i+1];. Dann geht es weiter zum nächsten i; Wenn array[i+1] != array[i]+1; dann range.end = array[i];

könnten Sie die Bereiche speichern in einem vector<range> ranges;

Druck wäre einfach:

for(int i = 0; i < ranges.size(); i++) { 
    range rng = (range)ranges.at(i); 
    printf("[%i-%i]", rng.start, rng.end); 
} 
0
; For all cells of the array 
    ;if current cell = prev cell + 1 -> range continues 
    ;if current cell != prev cell + 1 -> range ended 

int[] x = [2,3,4,5,10,18,19,20] 
string output = '['+x[0] 
bool range = false; --current range 
for (int i = 1; i > x[].length; i++) { 
    if (x[i+1] = [x]+1) { 
    range = true; 
    } else { //not sequential 
    if range = true 
    output = output || '-' 
    else 
    output = output || ',' 
    output.append(x[i]','||x[i+1]) 
    range = false; 
    } 

} 

So ähnlich.

23

Hier ist ein Algorithmus, die ich some time ago gemacht, die ursprünglich für C# geschrieben, jetzt habe ich es zu JavaScript portiert:

function getRanges(array) { 
    var ranges = [], rstart, rend; 
    for (var i = 0; i < array.length; i++) { 
    rstart = array[i]; 
    rend = rstart; 
    while (array[i + 1] - array[i] == 1) { 
     rend = array[i + 1]; // increment the index if the numbers sequential 
     i++; 
    } 
    ranges.push(rstart == rend ? rstart+'' : rstart + '-' + rend); 
    } 
    return ranges; 
} 

getRanges([2,3,4,5,10,18,19,20]); 
// returns ["2-5", "10", "18-20"] 
getRanges([1,2,3,5,7,9,10,11,12,14 ]); 
// returns ["1-3", "5", "7", "9-12", "14"] 
getRanges([1,2,3,4,5,6,7,8,9,10]) 
// returns ["1-10"] 
+7

würde vorschlagen, die Werte zuerst zu sortieren, so dass Sie mit gemischten Werten wie umgehen können: [1,3,2,6,5,7] – Tracker1

+1

Ich habe dies in npm https://www.npmjs.com/package/get- Bereiche –

1

Hier eine Version für Perl ist:

use strict; 
use warnings; 

my @numbers = (0,1,3,3,3,4,4,7,8,9,12, 14, 15, 19, 35, 35, 37, 38, 38, 39); 
@numbers = sort {$a <=> $b} @numbers ; # Make sure array is sorted. 

# Add "infinity" to the end of the array. 
$numbers[1+$#numbers] = undef ; 

my @ranges =() ; # An array where the range strings are stored. 

my $start_number = undef ; 
my $last_number = undef ; 
foreach my $current_number (@numbers) 
{ 
    if (!defined($start_number)) 
    { 
    $start_number = $current_number ; 
    $last_number = $current_number ; 
    } 
    else 
    { 
    if (defined($current_number) && (($last_number + 1) >= $current_number)) 
    { 
     $last_number = $current_number ; 
     next ; 
    } 
    else 
    { 
     if ($start_number == $last_number) 
     { 
     push(@ranges, $start_number) ; 
     } 
     else 
     { 
     push(@ranges, "$start_number-$last_number") ; 
     } 
     $start_number = $current_number ; 
     $last_number = $current_number ; 
    } 
    } 
} 

# Print the results 
print join(", ", @ranges) . "\n" ; 
# Returns "0-1, 3-4, 7-9, 12, 14-15, 19, 35, 37-39" 
+0

Eine kürzere Antwort von PerlMonks: [http://www.perlmonks.org/?node_id=87538](http://www.perlmonks.org/?node_id=87538] –

5

einfach Spaß mit Lösung von CMS:

function getRanges (array) { 
    for (var ranges = [], rend, i = 0; i < array.length;) { 
     ranges.push ((rend = array[i]) + ((function (rstart) { 
     while (++rend === array[++i]); 
     return --rend === rstart; 
     })(rend) ? '' : '-' + rend)); 
    } 
    return ranges; 
    } 
+0

++ für die Trick While-Schleife. Übrigens, das ist äquiv. 'Funktion getRanges (c) {für (var b = [], a, d = 0; d Orwellophile

0

Hier ist mein nehmen auf diese ...

function getRanges(input) { 

    //setup the return value 
    var ret = [], ary, first, last; 

    //copy and sort 
    var ary = input.concat([]); 
    ary.sort(function(a,b){ 
    return Number(a) - Number(b); 
    }); 

    //iterate through the array 
    for (var i=0; i<ary.length; i++) { 
    //set the first and last value, to the current iteration 
    first = last = ary[i]; 

    //while within the range, increment 
    while (ary[i+1] == last+1) { 
     last++; 
     i++; 
    } 

    //push the current set into the return value 
    ret.push(first == last ? first : first + "-" + last); 
    } 

    //return the response array. 
    return ret; 
}
5

Ich war nur auf der Suche nach genau diesem Ding. Ich brauchte eine PHP-Version, also portierte CMS die Lösung.Hier ist es für jeden, der diese Frage hält für die gleiche Sache suchen:

function getRanges($nums) 
{ 
    $ranges = array(); 

    for ($i = 0, $len = count($nums); $i < $len; $i++) 
    { 
     $rStart = $nums[$i]; 
     $rEnd = $rStart; 
     while (isset($nums[$i+1]) && $nums[$i+1]-$nums[$i] == 1) 
      $rEnd = $nums[++$i]; 

     $ranges[] = $rStart == $rEnd ? $rStart : $rStart.'-'.$rEnd; 
    } 

    return $ranges; 
} 
5

ich diese Antwort nützlich gefunden, aber erforderlich, um eine Python-Version:

def GroupRanges(items): 
    """Yields 2-tuples of (start, end) ranges from a sequence of numbers. 

    Args: 
    items: an iterable of numbers, sorted ascendingly and without duplicates. 

    Yields: 
    2-tuples of (start, end) ranges. start and end will be the same 
    for ranges of 1 number 
    """ 
    myiter = iter(items) 
    start = myiter.next() 
    end = start 
    for num in myiter: 
    if num == end + 1: 
     end = num 
    else: 
     yield (start, end) 
     start = num 
     end = num 
    yield (start, end) 


numbers = [1, 2, 3, 5, 6, 7, 8, 9, 10, 20] 
assert [(1, 3), (5, 10), (20, 20)] == list(GroupRanges(numbers)) 
assert [(1, 1)] == list(GroupRanges([1])) 
assert [(1, 10)] == list(GroupRanges([1, 2, 3, 4, 5, 6, 7, 8, 9, 10])) 
0

PHP

function getRanges($nums) { 
sort($nums); 
$ranges = array(); 

for ($i = 0, $len = count($nums); $i < $len; $i++) 
{ 
    $rStart = $nums[$i]; 
    $rEnd = $rStart; 
    while (isset($nums[$i+1]) && $nums[$i+1]-$nums[$i] == 1) 
     $rEnd = $nums[++$i]; 

    $ranges[] = $rStart == $rEnd ? $rStart : $rStart.'-'.$rEnd; 
} 

return $ranges; 
} 


echo print_r(getRanges(array(2,21,3,4,5,10,18,19,20))); 
echo print_r(getRanges(array(1,2,3,4,5,6,7,8,9,10))); 
+1

print_r wird bereits in stdout gedruckt, wenn Sie den optionalen zweiten Parameter nicht auf true setzen: echo print_r (array(), true); oder nur print_r (array()); –

0
import java.util.ArrayList; 
import java.util.Arrays; 



public class SequencetoRange { 

    /** 
    * @param args 
    */ 
    public static void main(String[] args) { 
    // TODO Auto-generated method stub 

     int num[] = {1,2,3,63,65,66,67,68,69,70,80,90,91,94,95,4,101,102,75,76,71}; 

     int l = num.length; 
     int i; 
     System.out.print("Given number : "); 
     for (i = 0;i < l;i++){ 
      System.out.print(" " + num[i]); 
     } 
     System.out.println("\n"); 
     Arrays.sort(num); 

     ArrayList newArray = new ArrayList(); 
     newArray = getRanges(num); 
     System.out.print("Range : "); 
     for(int y=0;y<newArray.size();y++) 
     { 
      System.out.print(" " +newArray.get(y)); 
     } 
    } 

    public static ArrayList getRanges(int num[]) 
    { 
     ArrayList ranges = new ArrayList(); 
     int rstart, rend; 
     int lastnum = num[num.length-1]; 
     for (int i = 0; i < num.length-1; i++) 
     {  
      rstart = num[i];  
      rend = rstart;  
      while (num[i + 1] - num[i] == 1) 
      {  
       rend = num[i + 1]; 
       // increment the index if the numbers sequential  
       if(rend>=lastnum) 
       { 
        break; 
       } 
       else 
       { 
        i++; 
       } 
      } 
      if(rstart==rend) 
      { 
       ranges.add(rend); 
      } 
      else 
      { 
       ranges.add(+rstart+"..."+rend); 
      } 
     } 
     return ranges; 
    } 
} 
1

In C#

public string compressNumberRange(string inputSeq) 
    { 
     //Convert String array to long List and removing the duplicates 
     List<long> longList = inputSeq.Split(',').ToList().ConvertAll<long>(s => Convert.ToInt64(s)).Distinct().ToList(); 

     //Sort the array 
     longList.Sort(); 

     StringBuilder builder = new StringBuilder(); 


     for (int itr = 0; itr < longList.Count(); itr++) 
     { 
      long first = longList[itr]; 
      long end = first; 

      while (longList[itr + 1] - longList[itr] == 1) //Seq check 
      { 
       end = longList[itr + 1]; 
       itr++; 
       if (itr == longList.Count() - 1) 
        break; 
      } 
      if (first == end) //not seq 
       builder.Append(first.ToString() + ","); 
      else //seq 
       builder.Append(first.ToString() + "-" + end.ToString() + ","); 
     } 

     return builder.ToString(); 
    } 
0

Ich habe meine eigene Methode geschrieben, die von Lo-Dash abhängig ist, aber gibt Ihnen nicht nur eine Reihe von Bereichen zurück, sondern gibt nur ein Array von Bereichsgruppen zurück.

[1,2,3,4,6,8,10] wird:

[[1,2,3,4],[6,8,10]] 

http://jsfiddle.net/mberkom/ufVey/

1

Hier eine Portierung von CMS-Code für BASH ist:

#!/usr/bin/env bash 
# vim: set ts=3 sts=48 sw=3 cc=76 et fdm=marker: # **** IGNORE ****** 
get_range() { RANGE= # <-- OUTPUT     **** THIS ****** 
    local rstart rend i arr=("[email protected]") # ported from **** JUNK ****** 
    for ((i=0 ; i < $# ; i++)); do # http://stackoverflow.com 
     ((rstart = arr[i]))   # /a/2270987/912236 
     rend=$rstart; while ((arr[i+1] - arr[i] == 1)); do 
     ((rend = arr[++i])); done; ((rstart == rend)) && 
    RANGE+=" $rstart" || RANGE+=" $rstart-$rend"; done; } # }}} 
0

Eine Anpassung von CMS's javascript solution für Cold Fusion

Es sortiert die Liste zuerst, so dass 1,3,2,4,5,8,9,10 (oder ähnlich) wird richtig in 1-5,8-10 konvertiert.

<cfscript> 
    function getRanges(nArr) { 
     arguments.nArr = listToArray(listSort(arguments.nArr,"numeric")); 
     var ranges = []; 
     var rstart = ""; 
     var rend = ""; 
     for (local.i = 1; i <= ArrayLen(arguments.nArr); i++) { 
      rstart = arguments.nArr[i]; 
      rend = rstart; 
      while (i < ArrayLen(arguments.nArr) and (val(arguments.nArr[i + 1]) - val(arguments.nArr[i])) == 1) { 
       rend = val(arguments.nArr[i + 1]); // increment the index if the numbers sequential 
       i++; 
      } 
      ArrayAppend(ranges,rstart == rend ? rstart : rstart & '-' & rend); 
     } 
     return arraytolist(ranges); 
    } 
</cfscript> 
+0

Danke ... Ich hatte eine ähnliche UDF geschrieben, aber sie hatte einen Fehler. Ich habe das so aktualisiert, dass es eine Liste oder ein Array akzeptiert und eine Subroutine hinzugefügt hat, um nicht-numerische Elemente zu trimmen und zu entfernen, bevor die numerische Sortierung durchgeführt wird. (Wenn dies nicht für vom Benutzer bereitgestellte Werte erfolgt, wird möglicherweise ein Fehler ausgegeben.) –

1

Sehr schöne Frage: hier ist mein Versuch:

function ranges(numbers){ 
    var sorted = numbers.sort(function(a,b){return a-b;}); 
    var first = sorted.shift(); 
    return sorted.reduce(function(ranges, num){ 
     if(num - ranges[0][1] <= 1){ 
      ranges[0][1] = num;   
     } else { 
      ranges.unshift([num,num]); 
     } 
     return ranges; 
    },[[first,first]]).map(function(ranges){ 
     return ranges[0] === ranges[1] ? 
      ranges[0].toString() : ranges.join('-'); 
    }).reverse(); 
} 

Demo on JSFiddler

0

Hier ist, was ich zusammen in Swift. Es eliminiert Duplikate und sortiert das Array zuerst, und es macht nichts, wenn es ein leeres Array oder ein Array von einem gegeben wird.

func intArrayToString(array: [Int]) -> String { 
    var intArray = Array(Set(array)) 
    intArray.sortInPlace() 
    if intArray.count == 0 { 
     return "" 
    } 
    var intString = "\(intArray[0])" 
    if intArray.count > 1 { 
     for j in 1..<intArray.count-1 { 
      if intArray[j] == intArray[j-1]+1 { 
       if intArray[j] != intArray[j+1]-1 { 
        intString += "-\(intArray[j])" 
       } 
      } else { 
       intString += ",\(intArray[j])" 
      } 
     } 
     if intArray.last! == intArray[intArray.count-2]+1 { 
      intString += "-\(intArray.last!)" 
     } else { 
      intString += ",\(intArray.last!)" 
     } 
    } 
    return intString 
} 
0

Tiny ES6-Modul für euch. Es akzeptiert eine Funktion, um zu bestimmen, wann wir die Sequenz unterbrechen müssen (breakDetectorFunc param - Standard ist das Einfache für Integer-Sequenz-Eingabe). HINWEIS: da die Eingabe abstrakt ist - es gibt keine automatische Sortierung vor der Verarbeitung, so dass, wenn die Sequenz nicht sortiert ist - es kann vor diesem Modul

function defaultIntDetector(a, b){ 
    return Math.abs(b - a) > 1; 
} 

/** 
* @param {Array} valuesArray 
* @param {Boolean} [allArraysResult=false] if true - [1,2,3,7] will return [[1,3], [7,7]]. Otherwise [[1.3], 7] 
* @param {SequenceToIntervalsBreakDetector} [breakDetectorFunc] must return true if value1 and value2 can't be in one sequence (if we need a gap here) 
* @return {Array} 
*/ 
const sequenceToIntervals = function (valuesArray, allArraysResult, breakDetectorFunc) { 
    if (!breakDetectorFunc){ 
     breakDetectorFunc = defaultIntDetector; 
    } 
    if (typeof(allArraysResult) === 'undefined'){ 
     allArraysResult = false; 
    } 

    const intervals = []; 
    let from = 0, to; 
    if (valuesArray instanceof Array) { 
     const cnt = valuesArray.length; 
     for (let i = 0; i < cnt; i++) { 
      to = i; 
      if (i < cnt - 1) { // i is not last (to compare to next) 
       if (breakDetectorFunc(valuesArray[i], valuesArray[i + 1])) { 
        // break 
        appendLastResult(); 
       } 
      } 
     } 
     appendLastResult(); 
    } else { 
     throw new Error("input is not an Array"); 
    } 

    function appendLastResult(){ 
     if (isFinite(from) && isFinite(to)) { 
      const vFrom = valuesArray[from]; 
      const vTo = valuesArray[to]; 

      if (from === to) { 
       intervals.push(
        allArraysResult 
         ? [vFrom, vTo] // same values array item 
         : vFrom // just a value, no array 
       ); 
      } else if (Math.abs(from - to) === 1) { // sibling items 
       if (allArraysResult) { 
        intervals.push([vFrom, vFrom]); 
        intervals.push([vTo, vTo]); 
       } else { 
        intervals.push(vFrom, vTo); 
       } 
      } else { 
       intervals.push([vFrom, vTo]); // true interval 
      } 
      from = to + 1; 
     } 
    } 

    return intervals; 
}; 

module.exports = sequenceToIntervals; 

/** @callback SequenceToIntervalsBreakDetector 
@param value1 
@param value2 
@return bool 
*/ 

erste Argument Aufruf wird die Eingangssequenz sortiert Array, das zweite ist ein boolesches Flag, das den Ausgabemodus steuert: wenn true - ein einzelnes Element (außerhalb der Intervalle) wird als Array zurückgegeben: [1,7], [9,9], [10,10], [12,20], andernfalls Einzelstücke zurückgeführt, wie sie in dem Eingangsfeld

für Ihre Abtastwerteingang erscheinen

[2,3,4,5,10,18,19,20] 

wird zurückgegeben:

sequenceToIntervals([2,3,4,5,10,18,19,20], true) // [[2,5], [10,10], [18,20]] 
sequenceToIntervals([2,3,4,5,10,18,19,20], false) // [[2,5], 10, [18,20]] 
sequenceToIntervals([2,3,4,5,10,18,19,20]) // [[2,5], 10, [18,20]] 
Verwandte Themen