2010-02-16 262 views
20

在javascript中如何將數組中的數字序列轉換爲數字範圍?如何將數組中的數字序列轉換爲數字範圍

例如。 [2,3,4,5,10,18,19,20][2-5,10,18-20]

+0

你是如何確定享受一系列的開始和結束? – Sampson 2010-02-16 05:45:43

+5

@gokul:我編輯你的問題(從標題刪除例如,格式化的正文)。您可以通過正確設置問題來激勵人們提供幫助。 – 2010-02-16 05:45:47

回答

1

如果你只是想表示一個範圍內的字符串,那麼你會發現你的序列的中點,並(在你的例子10)成爲你的中間值。然後,您會抓取序列中的第一個項目以及緊接在中點之前的項目,並構建您的第一個序列表示。你可以按照相同的步驟獲得最後一個項目,以及緊接在中間點之後的項目,並建立最後一個序列的表示。

// 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 

在線演示:http://jsbin.com/uvahi/edit

+3

輸出不是1-10,因爲數字1-10依次出現而沒有丟失? – 2010-02-16 07:53:56

0

你可以遍歷號碼,看看接下來的數大於1,則當前數目。所以有一個:

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

其中如果array[i+1] == array[i]+1;(其中,i是當前觀察到的數目) 然後range.end = array[i+1];。然後你進入下一個i;如果array[i+1] != array[i]+1;然後range.end = array[i];

你可以存儲範圍在vector<range> ranges;

印刷很容易:

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; 
    } 

} 

類似的東西。

23

這是一種算法,我做了some time ago,最初是爲C#寫的,現在我把它移植到JavaScript的:

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

會建議先排序值,所以你可以處理混合值,如:[1,3,2,6,5,7] – Tracker1 2010-02-16 07:57:39

+1

我把它放在npm https://www.npmjs.com/package/get-範圍 – 2016-09-17 08:40:32

1

這裏是一個Perl的一個版本:

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

來自PerlMonks的較短答案:[http://www.perlmonks.org/?node_id=87538](http://www.perlmonks.org/?node_id=87538) – 2011-09-09 20:27:17

5

只要有樂趣來自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

++ for trick while循環。順便說一句,這是相等的。函數getRanges(c){for(var b = [],a,d = 0; d Orwellophile 2014-01-12 03:01:52

0

下面是我對此的看法...

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

我只是在尋找這個確切的東西。我需要一個PHP版本,以便移植CMS的解決方案。這是任何人誰被這個問題尋找同樣的事情停止:

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

我發現這個答案是有用的,但需要一個Python版本:

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

除非將可選的第二個參數設置爲true,否則print_r已經打印到stdout:echo print_r(array(),true);或者只是print_r(array()); – 2012-07-18 22:00:19

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

在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

我寫我自己的方法,這是依賴於羅短跑,但不只是給你回的範圍數組,相反,它只是返回範圍組的陣列。

[1,2,3,4,6,8,10]變爲:

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

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

1

下面是CMS的代碼BASH端口:

#!/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

冷聚變

CMS's javascript solution適應它首先做排序的列表,以便1,3,2,4,5,8,9,10(或類似)正確轉換爲1-5,8-10

<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

謝謝...我寫了一個類似的UDF,但它遭受了一個錯誤。我更新了這個,所以它會接受一個列表或數組,並在嘗試數字排序之前添加一個子例程來修剪和刪除非數字項目。 (如果沒有爲用戶提供的值執行此操作,則可能會引發錯誤。) – 2016-08-25 15:16:01

1

非常好的問題:這是我的嘗試:

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

這是我放在一起的斯威夫特。它首先消除重複並對數組進行排序,並不介意它是否給出了一個空數組或一個數組。

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

微小的ES6模塊爲你們。它接受一個函數來確定我們什麼時候必須破壞序列(breakDetectorFunc param - 默認是整數序列輸入的簡單事情)。 注意:由於輸入是抽象的 - 有沒有自動分揀處理之前,因此,如果您的序列是沒有排序 - 在調用該模塊

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 
*/ 

第一個參數做到這一點是輸入序列排序後的數組,第二個是一布爾標誌控制輸出模式:如果爲真 - 單個項目(間隔外)將被反正返回數組:[1,7],[9,9],[10,10],[12,20],否則單品返回它們出現的輸入數組

在爲您的樣品輸入

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

則回覆:

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]] 
相關問題