Adjacent number algorithm grouper

前端 未结 13 1702
不思量自难忘°
不思量自难忘° 2021-02-15 06:55

By which I mean this:

Given the input set of numbers:

1,2,3,4,5 becomes \"1-5\".

1,2,3,5,7,9,10,11,12,14 becomes \"1-3, 5, 7, 9-12, 14\"

This is

相关标签:
13条回答
  • 2021-02-15 07:38

    Short and sweet Ruby

    def range_to_s(range)
      return range.first.to_s if range.size == 1
      return range.first.to_s + "-" + range.last.to_s
    end
    
    def format_ints(ints)
      range = []
      0.upto(ints.size-1) do |i|
        range << ints[i]
        unless (range.first..range.last).to_a == range
          return range_to_s(range[0,range.length-1]) + "," + format_ints(ints[i,ints.length-1])
        end
      end
      range_to_s(range)  
    end
    
    0 讨论(0)
  • 2021-02-15 07:41

    Looks clear and straightforward to me. You can simplify a bit if you either assume the input array is sorted, or sort it yourself before further processing.

    The only tweak I'd suggest would be to reverse the subtraction:

    int difference = (current - lastNumber);

    ... simply because I find it easier to work with positive differences. But your code is a pleasure to read!

    0 讨论(0)
  • 2021-02-15 07:45

    Here's my Haskell entry:

    runs lst = map showRun $ runs' lst
    
    runs' l = reverse $ map reverse $ foldl newOrGlue [[]] l 
    
    showRun [s] = show s
    showRun lst = show (head lst) ++ "-" ++ (show $ last lst)
    
    newOrGlue [[]] e = [[e]]
    newOrGlue (curr:other) e | e == (1 + (head curr)) = ((e:curr):other)
    newOrGlue (curr:other) e | otherwise              = [e]:(curr:other)
    

    and a sample run:

    T> runs [1,2,3,5,7,9,10,11,12,14]
    
    ["1-3","5","7","9-12","14"]
    
    0 讨论(0)
  • 2021-02-15 07:46

    Perl

    With input validation/pre-sorting

    You can easily get the result as a LoL if you need to do something more fancy than just return a string.

    #!/usr/bin/perl -w
    
    use strict;
    use warnings;
    
    use Scalar::Util qw/looks_like_number/;
    
    sub adjacenify {
        my @input = @_;  
    
        # Validate and sort
        looks_like_number $_ or
            die "Saw '$_' which doesn't look like a number" for @input;
        @input = sort { $a <=> $b } @input;
    
        my (@output, @range);
        @range = (shift @input);
        for (@input) {
            if ($_ - $range[-1] <= 1) {
                push @range, $_ unless $range[-1] == $_; # Prevent repetition
            }
            else {
                push @output, [ @range ];
                @range = ($_); 
            }
        }   
        push @output, [ @range ] if @range;
    
        # Return the result as a string. If a sequence is size 1, then it's just that number.
        # Otherwise, it's the first and last number joined by '-'
        return join ', ', map { 1 == @$_ ? @$_ : join ' - ', $_->[0], $_->[-1] } @output;
    }
    
    print adjacenify( qw/1 2 3 5 7 9 10 11 12 14/ ), "\n";
    print adjacenify( 1 .. 5 ), "\n";
    print adjacenify( qw/-10 -9 -8 -1 0 1 2 3 5 7 9 10 11 12 14/ ), "\n";
    print adjacenify( qw/1 2 4 5 6 7 100 101/), "\n";
    print adjacenify( qw/1 62/), "\n";
    print adjacenify( qw/1/), "\n";
    print adjacenify( qw/1 2/), "\n";
    print adjacenify( qw/1 62 63/), "\n";
    print adjacenify( qw/-2 0 0 2/), "\n";
    print adjacenify( qw/-2 0 0 1/), "\n";
    print adjacenify( qw/-2 0 0 1 2/), "\n";
    

    Output:

    1 - 3, 5, 7, 9 - 12, 14
    1 - 5
    -10 - -8, -1 - 3, 5, 7, 9 - 12, 14
    1 - 2, 4 - 7, 100 - 101
    1, 62
    1
    1 - 2
    1, 62 - 63
    -2, 0, 2
    -2, 0 - 1
    -2, 0 - 2
    -2, 0 - 2
    

    And a nice recursive solution:

    sub _recursive_adjacenify($$);
    sub _recursive_adjacenify($$) {
        my ($input, $range) = @_;
    
        return $range if ! @$input;
    
        my $number = shift @$input;
    
        if ($number - $range->[-1] <= 1) {
            return _recursive_adjacenify $input, [ @$range, $number ];
        }
        else {
            return $range, _recursive_adjacenify $input, [ $number ];
        }
    }
    
    sub recursive_adjacenify {
        my @input = @_;
    
        # Validate and sort
        looks_like_number $_ or
            die "Saw '$_' which doesn't look like a number" for @input;
        @input = sort { $a <=> $b } @input;
    
        my @output = _recursive_adjacenify \@input, [ shift @input ];
    
        # Return the result as a string. If a sequence is size 1, 
        # then it's just that number.
        # Otherwise, it's the first and last number joined by '-'
        return join ', ', map { 2 == @$_ && $_->[0] == $_->[1] ? $_->[0] : 
                                1 == @$_ ? @$_ : 
                                join ' - ', $_->[0], $_->[-1] } @output;
    
    }
    
    0 讨论(0)
  • 2021-02-15 07:48

    See How would you display an array of integers as a set of ranges? (algorithm)

    My answer to the above question:

    void ranges(int n; int a[n], int n)
    {
      qsort(a, n, sizeof(*a), intcmp);
      for (int i = 0; i < n; ++i) {
        const int start = i;
        while(i < n-1 and a[i] >= a[i+1]-1)
          ++i;
        printf("%d", a[start]);
        if (a[start] != a[i])
          printf("-%d", a[i]);
        if (i < n-1)
          printf(",");
      }
      printf("\n");
    }
    
    0 讨论(0)
  • 2021-02-15 07:48

    Pure functional Python:

    #!/bin/env python
    
    def group(nums):
        def collect((acc, i_s, i_e), n):
            if n == i_e + 1: return acc, i_s, n
            return acc + ["%d"%i_s + ("-%d"%i_e)*(i_s!=i_e)], n, n
        s = sorted(nums)+[None]
        acc, _, __ = reduce(collect, s[1:], ([], s[0], s[0]))
        return ", ".join(acc)
    
    assert group([1,2,3,5,7,9,10,11,12,14]) == "1-3, 5, 7, 9-12, 14"
    
    0 讨论(0)
提交回复
热议问题