In javascript come convertire la sequenza di numeri in una matrice in un intervallo di numeri?Come convertire la sequenza di numeri in una matrice in un intervallo di numeri
es. [2,3,4,5,10,18,19,20]
a [2-5,10,18-20]
In javascript come convertire la sequenza di numeri in una matrice in un intervallo di numeri?Come convertire la sequenza di numeri in una matrice in un intervallo di numeri
es. [2,3,4,5,10,18,19,20]
a [2-5,10,18-20]
Se si desidera semplicemente una stringa che rappresenta un intervallo, si troverà il punto centrale della sequenza e questo diventerà il valore medio (10 nell'esempio). Dovresti quindi afferrare il primo elemento nella sequenza e l'elemento che ha immediatamente preceduto il punto medio e creare la rappresentazione della prima sequenza. Seguirai la stessa procedura per ottenere il tuo ultimo oggetto e l'oggetto che segue immediatamente il tuo punto medio e costruisci la tua rappresentazione dell'ultima sequenza.
// 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
L'output non dovrebbe essere 1-10, poiché i numeri 1-10 appaiono in sequenza senza nessuno mancante? –
Si potrebbe iterare i numeri e vedere se il numero successivo è 1 grande allora il numero attuale. Quindi avere un:
struct range {
int start;
int end;
} range;
dove se array[i+1] == array[i]+1;
(dove i è il numero attualmente osservato) poi range.end = array[i+1];
. Quindi procedi al prossimo i
; Se poi array[i+1] != array[i]+1;
range.end = array[i];
è possibile memorizzare gli intervalli in una stampa vector<range> ranges;
sarebbe stato facile:
for(int i = 0; i < ranges.size(); i++) {
range rng = (range)ranges.at(i);
printf("[%i-%i]", rng.start, rng.end);
}
; 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;
}
}
Qualcosa del genere.
Ecco un algoritmo che ho fatto some time ago, originariamente scritto per C#, ora ho portato a 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"]
suggerirebbe di ordinare prima i valori, quindi puoi gestire valori misti come: [1,3,2,6,5,7] – Tracker1
Lo metto in npm https://www.npmjs.com/package/get- range –
Ecco una versione per 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"
Una risposta più breve da PerlMonks: [http://www.perlmonks.org/?node_id=87538](http://www.perlmonks.org/?node_id=87538) –
Basta divertirsi con soluzione da 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;
}
++ per il trucco mentre il ciclo. btw, questo è equiv. 'function getRanges (c) {for (var b = [], a, d = 0; d
Ecco il mio prendere su questo ...
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;
}
Stavo solo cercando questa cosa esatta. Avevo bisogno di una versione PHP in modo tale che la soluzione di CMS fosse stata trasferita.Ecco, per chi si ferma a questa domanda cercando la stessa cosa:
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;
}
ho trovato questa risposta utile, ma aveva bisogno di una versione di 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]))
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)));
print_r stampa già su stdout a meno che non si imposti il secondo parametro opzionale su true: echo print_r (array(), true); o semplicemente print_r (array()); –
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;
}
}
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();
}
Ho scritto il mio metodo che dipende da Lo-Dash, ma non ti restituisce una serie di intervalli, ma restituisce semplicemente una serie di gruppi di intervalli.
[1,2,3,4,6,8,10] diventa:
[[1,2,3,4],[6,8,10]]
Ecco un porto di codice del CMS per 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; } # }}}
Un adattamento di CMS's javascript solution per Cold Fusion
Si ordina innanzitutto l'elenco in modo che 1,3,2,4,5,8,9,10
(o simile) converte correttamente in 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>
Grazie ... Avevo scritto una UDF simile, ma soffriva di un bug. Ho aggiornato questo modo per accettare una lista o un array e ho aggiunto una subroutine per tagliare e rimuovere elementi non numerici prima di tentare l'ordinamento numerico. (Se questo non viene fatto per i valori forniti dall'utente, può essere generato un errore.) –
Bellissima domanda: ecco il mio tentativo:
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();
}
Ecco quello che ho messo insieme in Swift. Elimina i duplicati e ordina l'array per primo, e non gli importa se ha un array vuoto o un array di uno.
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
}
Piccolo modulo ES6 per voi ragazzi. Accetta una funzione per determinare quando è necessario interrompere la sequenza (breakDetectorFunc param - default è la cosa più semplice per l'input della sequenza intera). AVVISO: dal momento di ingresso è astratta - non c'è auto-selezione prima della lavorazione, quindi se la sequenza non è ordinato - serie non è prima di chiamare questo modulo
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
*/
primo argomento è la sequenza di ingresso ordinato, secondo è un flag booleano che controlla la modalità di output: se true - un singolo elemento (al di fuori degli intervalli) verrà comunque restituito come array: [1,7], [9,9], [10,10], [12,20], altrimenti singole voci restituiti come appaiono nella matrice di ingresso
per il vostro input di esempio
[2,3,4,5,10,18,19,20]
restituirà:
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]]
Come si determina dove inizia e termina un intervallo? – Sampson
@gokul: ho modificato la tua domanda (esempio rimosso dal titolo, corpo formattato). Puoi motivare le persone ad aiutare formattando correttamente la tua domanda. –