Random Golf of the Day #1: Shuffle an Array

35

6

About the Series

I will be running a little series of code-golf challenges revolving around the theme of randomness. This will basically be a 9-Hole Golf Course, but spread out over several questions. You may participate in any challenge individually as if it was a normal question.

However, I will maintain a leaderboard across all challenges. The series will run over 9 challenges (for now), one posted every few days. Every user who participates in all 9 challenges is eligible for winning the entire series. Their overall score is the sum of their shortest submissions on each challenge (so if you answer a challenge twice, only the better answer one is counted towards the score). If anyone holds the top spot on this overall leaderboard for 28 days I will award them a bounty of 500 rep.

Although I have a bunch of ideas lined up for the series, the future challenges are not set in stone yet. If you have any suggestions, please let me know on the relevant sandbox post.

Hole 1: Shuffle an Array

The first task is pretty simple: given a non-empty array of integers, shuffle it randomly. There are a few rules though:

  • Every possible permutation must be returned with the same probability (so the shuffle should have a uniform distribution). You can check if your algorithm is uniform/unbiased by implementing it in JavaScript on Will it Shuffle, which will produce a matrix of the biases - the result should look as uniform as their built-ins Fisher-Yates or sort (random order).
  • You must not use any built-in or 3rd-party method to shuffle the array or generate a random permutation (or enumerate all permutations). In particular, the only built-in random function you may use is getting a single random number at a time. You may assume that any built-in random number method runs in O(1) and is perfectly uniform over the requested interval (in a mathematical sense - you may ignore details of floating-point representation here). If your language lets you obtain a list of m random numbers at once, you may use this facility, provided the m numbers are independent of each other, and you count it as O(m).
  • Your implementation must not exceed a time complexity of O(N), where N is the size of the array to be shuffled. For instance, you cannot "sort by random numbers".
  • You may either shuffle the array in place, or create a new array (in which case the old array may be modified however you like).

You may write a full program or a function and take input via STDIN, command-line argument, function argument or prompt and produce output via return value or by printing to STDOUT (or closest alternative). If you write a function that shuffles the array in place, you don't need to return it of course (provided your language lets you access the modified array after the function returns).

Input and output may be in any convenient list or string format, but must support arbitrary integers in the range -231 ≤ x < 231. In principle, your code should work for arrays up to length 231, although this doesn't necessarily have to fit in your memory or complete within a reasonable amount of time. (I just don't want to see arbitrary size limits to hardcode loops or something.)

This is code golf, so the shortest submission (in bytes) wins.

Leaderboard

The following snippet will generate a leaderboard across all challenges of the series.

To make sure that your answers show up, please start every answer with a headline, using the following Markdown template:

# Language Name, N bytes

where N is the size of your submission. If you improve your score, you can keep old scores in the headline, by striking them through. For instance:

# Ruby, <s>104</s> <s>101</s> 96 bytes

(The language is not currently shown, but the snippet does require and parse it, and I may add a by-language leaderboard in the future.)

/* Configuration */

var QUESTION_IDs = [45302, 45447, 46991, 49394, 51222, 66319, 89621, 120472]; // Obtain this from the url
// It will be like http://XYZ.stackexchange.com/questions/QUESTION_ID/... on any question page
var ANSWER_FILTER = "!.FjwQBrX2KXuFkv6p2lChi_RjzM19";

/* App */

var answers = [], page = 1, currentQ = -1;

function answersUrl(index) {
  return "https://api.stackexchange.com/2.2/questions/" +  QUESTION_IDs.join(";") + "/answers?page=" + index + "&pagesize=100&order=desc&sort=creation&site=codegolf&filter=" + ANSWER_FILTER;
}


function getAnswers() {
  $.ajax({
    url: answersUrl(page++),
    method: "get",
    dataType: "jsonp",
    crossDomain: true,
    success: function (data) {
      answers.push.apply(answers, data.items);
      if (data.has_more) getAnswers();
      else process();
    }
  });
}

getAnswers();

var SIZE_REG = /\d+(?=[^\d&]*(?:&lt;(?:s&gt;((?!&gt;).)*&lt;\/s&gt;|((?!&gt;).)+&gt;)[^\d&]*)*$)/;
var NUMBER_REG = /\d+/;
var LANGUAGE_REG = /^#*\s*([^\n,]+)(?=,)/;//

function shouldHaveHeading(a) {
  var pass = false;
  var lines = a.body_markdown.split("\n");
  try {
    pass |= /^#/.test(a.body_markdown);
    pass |= ["-", "="]
              .indexOf(lines[1][0]) > -1;
    pass &= LANGUAGE_REG.test(a.body_markdown);
  } catch (ex) {}
  return pass;
}

function shouldHaveScore(a) {
  var pass = false;
  try {
    pass |= SIZE_REG.test(a.body_markdown.split("\n")[0]);
  } catch (ex) {}
  if (!pass) console.log(a);
  return pass;
}

function getAuthorName(a) {
  return a.owner.display_name;
}

function getAuthorId(a) {
  return a.owner.user_id;
}

function process() {
  answers = answers.filter(shouldHaveScore)
                   .filter(shouldHaveHeading);
  answers.sort(function (a, b) {
    var aB = +(a.body_markdown.split("\n")[0].match(SIZE_REG) || [Infinity])[0],
        bB = +(b.body_markdown.split("\n")[0].match(SIZE_REG) || [Infinity])[0];
    return aB - bB
  });

  var users = {};
  answers.forEach(function (a) {
    var headline = a.body_markdown.split("\n")[0];
    var question = QUESTION_IDs.indexOf(a.question_id);
    var size = parseInt((headline.match(SIZE_REG)||[0])[0]);
    var language = headline.match(LANGUAGE_REG)[1];
    var user = getAuthorName(a);
    var userId = getAuthorId(a);
    if (!users[userId]) users[userId] = {name: user, nAnswer: 0, answers: []};
    if (!users[userId].answers[question]) {
      users[userId].answers[question] = {size: Infinity};
      users[userId].nAnswer++;
    }
    if (users[userId].answers[question].size > size) {
      users[userId].answers[question] = {size: size, link: a.share_link}
    }
  });
  
  
  var sortedUsers = [];
  for (var userId in users)
    if (users.hasOwnProperty(userId)) {
      var user = users[userId];
      user.score = 0;
      user.completedAll = true;
      for (var i = 0; i < QUESTION_IDs.length; ++i) {
        if (user.answers[i])
          user.score += user.answers[i].size;
        else
          user.completedAll = false;
      }
      sortedUsers.push(user);
    }  
  
  sortedUsers.sort(function (a, b) {
    if (a.nAnswer > b.nAnswer) return -1;
    if (b.nAnswer > a.nAnswer) return 1;
    return a.score - b.score;
  });
  
  var place = 1;
  for (var i = 0; i < sortedUsers.length; ++i) {
    var user = sortedUsers[i];
    var row = '<tr><td>'+ place++ +'.</td><td>'+user.name+'</td>';
    for (var j = 0; j < QUESTION_IDs.length; ++j) {
      var answer = user.answers[j];
      if (answer)
        row += '<td><a href="'+answer.link+'">'+answer.size+'</a></td>';
      else
        row += '<td class="missing"></td>';
    }
    row += '<td></td>';
    if (user.completedAll)
      row += '<td class="total">'+user.score+'</td>';
    else
      row += '<td class="total missing">'+user.score+'</td>';
    row += '</tr>';
    $("#users").append(row);
  }
}
body { text-align: left !important}

#leaderboard {
  width: 500px; 
}

#answer-list {
  padding: 10px;
  width: 290px;
  float: left;
}

#language-list {
  padding: 10px;
  width: 290px;
  float: left;
}

table thead {
  font-weight: bold;
}

table td {
  padding: 5px;
}

td.total {
  font-weight: bold;
  text-align: right;
}

td.missing {
  background: #bbbbbb;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<link rel="stylesheet" type="text/css" href="//cdn.sstatic.net/codegolf/all.css?v=83c949450c8b">
<div id="leaderboard">
  <h2>Leaderboard</h2>
  <p>
    Missing scores are shown as grey cells. A grey total indicates that the user has not participated in all challenges and is not eligible for the overall victory yet.
  </p>
  <table class="_user-list">
    <thead>
      <tr><td></td><td>User</td>
        <td><a href="https://codegolf.stackexchange.com/q/45302/8478">#1</a></td>
        <td><a href="https://codegolf.stackexchange.com/q/45447/8478">#2</a></td>
        <td><a href="https://codegolf.stackexchange.com/q/46991/8478">#3</a></td>
        <td><a href="https://codegolf.stackexchange.com/q/49394/8478">#4</a></td>
        <td><a href="https://codegolf.stackexchange.com/q/51222/8478">#5</a></td>
        <td><a href="https://codegolf.stackexchange.com/q/66319/8478">#6</a></td>
        <td><a href="https://codegolf.stackexchange.com/q/89621/8478">#7</a></td>
        <td><a href="https://codegolf.stackexchange.com/q/120472/8478">#8</a></td>
        <td></td><td>Total</td>
      </tr>
    </thead>
    <tbody id="users">

    </tbody>
  </table>
</div>
<table style="display: none">
  <tbody id="answer-template">
    <tr><td>{{NAME}}</td><td>{{LANGUAGE}}</td><td>{{SIZE}}</td><td><a href="{{LINK}}">Link</a></td></tr>
  </tbody>
</table>
<table style="display: none">
  <tbody id="language-template">
    <tr><td>{{LANGUAGE}}</td><td>{{NAME}}</td><td>{{SIZE}}</td><td><a href="{{LINK}}">Link</a></td></tr>
  </tbody>
</table>

Martin Ender

Posted 2015-02-03T14:13:38.343

Reputation: 184 808

7

I am disappointed that we are not allowed to be "clever" and use library functions other than "get a random number". Do we want to look at yet another 69 implementations of Fisher-Yates shuffling? Please consider removing this rule in future tasks. Also, why a limit on time complexity? Please consider relaxing it to at least O(n^2); I also think someone might find an especially golfed implementation if you allow O(n!).

– anatolyg – 2015-02-03T20:58:36.007

7@anatolyg Removing the restrictions amounts to every answer being either sortby(random) (the reason for the time restriction) or simply .shuffle() (the reason for the built-ins restriction), which I think is a lot less clever than having to implement Fisher-Yates or some other approach. – Martin Ender – 2015-02-03T21:03:44.863

1If shuffling in place, does a function have to return the array, or is it enough that it is modified? Can I write a function for shuffle(array) instead of newArray=shuffle(array)? – Geobits – 2015-02-04T02:30:53.333

Nitpicking: your claim that you cannot sort by random numbers, plus the restriction of fixed size integers are incompatible. You can sort in linear time if the size of the elements is fixed, what you cannot do is sorting by comparisons only. – Bakuriu – 2015-02-04T06:46:29.303

1@Bakuriu Claiming that you can sort in linear time if the numbers are fixed is a bit like claiming you can do anything in O(1) if the input sizes are fixed. Also the relevant restriction is fixed-size arrays, not fixed-size integers - because the array size determines how large you need your random numbers to be. Anyway, the limitation on time complexity are of course for the general algorithm you implement, whereas the limits on input sizes are in place so you don't have to use arbitrary-precision integers if your language doesn't use them out of the box. – Martin Ender – 2015-02-04T09:48:06.360

@Geobits The former is fine. I admit, the spec is currently a bit contradictory in that - will fix. – Martin Ender – 2015-02-04T09:48:54.293

For FUZxxl's J solution and aditsu's CJam solution (and maybe others?), while the algorithms used could have linear runtime, the implementations have quadratic runtime. Due to the languages used, for each digit shuffled, memory operations that take linear time with respect to the size of the input are performed. So unfortunately, I believe that these solutions (and probably any in those languages) do not meet the current requirements. – Runer112 – 2015-02-04T17:07:42.770

Can the function take its argument as a global? – kirbyfan64sos – 2015-02-08T22:06:14.307

@kirbyfan64sos No, that would essentially just be a snippet and not a function. – Martin Ender – 2015-02-08T22:07:57.957

2Why is Adám's solution coming up as 43319 bytes when it's actually 14? – boboquack – 2017-05-14T00:10:05.413

@boboquack Because of how stupidly answers are scanned for scores. I edited the answer to fix it. – Martin Ender – 2017-05-14T19:50:59.413

Answers

20

Dyalog APL, 25 24 bytes

First for the 25-character solution: i{⊃a[⍺⍵]←a[⍵⍺]}¨?i←⌽⍳⍴a←⎕

                      a←⎕ ⍝ evaluated input, assign to "a"
                     ⍴a   ⍝ length
                    ⍳⍴a   ⍝ 1 2 .. length
                   ⌽⍳⍴a   ⍝ length .. 2 1
                 i←       ⍝ assign to "i"
                ?i        ⍝ random choices: (1..length)(1..length-1)..(1 2)(1)
i{            }¨?i        ⍝ for each index ⍺ and corresponding random choice ⍵
   a[⍺⍵]←a[⍵⍺]            ⍝ swap a[⍺] and a[⍵]
        ←                 ⍝ in Dyalog, assignment returns its right-hand side
  ⊃                       ⍝ first element, i.e. a[⍵]
                          ⍝ the result from {} is an array of all those a[⍵]

After some equivalence transformations on the above:

i {}¨ ?i  ←→  i {}¨∘? i   ⍝ because A f∘g B ←→ A f g B
          ←→  {}¨∘?⍨ i    ⍝ because f⍨ B ←→ B f B

we can get rid of the assignment i← and save a character:

{⊃a[⍺⍵]←a[⍵⍺]}¨∘?⍨⌽⍳⍴a←⎕

ngn

Posted 2015-02-03T14:13:38.343

Reputation: 11 449

3... mind. blown. – danwyand – 2015-02-04T18:03:55.590

1a language I have to read right to left?? wow! – Luminous – 2015-02-04T19:16:39.757

5@Luminous as is often the case with mathematical notation: sin cos ln sqrt x – ngn – 2015-02-04T19:26:04.833

4@ngn when you put it that way that makes my previous comment look laughable. ha. – Luminous – 2015-02-04T19:39:29.240

I object. According to https://mothereff.in/byte-counter, this solution is 51 bytes! Therefore, I suggest that some of the other solutions are shorter.

– ronalchn – 2015-02-05T06:25:39.387

5

@ronalchn There are 8-bit encodings for APL, like this one or this other one; I heard Dyalog uses one of these, as an alternative to Unicode.

– anatolyg – 2015-02-05T08:43:05.017

@ngn it's often the case in many languages. f(g(h(x))) – undergroundmonorail – 2015-02-19T19:14:22.790

1@Luminous You read APL left to right but it's evaluated right to left. – FUZxxl – 2015-05-06T10:27:39.617

12

80386 machine code, 44 24 bytes

Hexdump of the code:

60 8b fa 0f c7 f0 33 d2 f7 f1 49 8b 04 8f 87 04
97 89 04 8f 75 ed 61 c3

Thanks to FUZxxl, who suggested using the rdrand instruction.

Here is the source code (can be compiled by Visual Studio):

__declspec(naked) void __fastcall shuffle(unsigned size, int array[])
{
    // fastcall convention:
    // ecx = size
    // edx = array
    _asm
    {
        pushad;             // save registers
        mov edi, edx;       // edi now points to the array

    myloop:
        rdrand eax;         // get a random number
        xor edx, edx;
        div ecx;            // edx = random index in the array

        dec ecx;            // count down
        mov eax, [edi + 4 * ecx];   // swap elements
        xchg eax, [edi + 4 * edx];  // swap elements
        mov [edi + 4 * ecx], eax;   // swap elements
        jnz myloop;

        popad;              // restore registers
        ret;
    }
}

Yet another Fisher-Yates implementation. Most of the golfing was achieved by passing parameters in registers.

anatolyg

Posted 2015-02-03T14:13:38.343

Reputation: 10 719

1You could have also used rdrand for shits and giggles. – FUZxxl – 2015-02-04T13:31:14.163

@FUZxxl I totally forgot about it! Too bad it removes the most interesting part about my answer... – anatolyg – 2015-02-04T13:37:12.107

9

Java, 88 101

A basic Fisher-Yates shuffle does the trick. I get the feeling it'll be used pretty commonly here, since it's quick and easy to implement. There's some loop/assignment cramming here, but there's honestly not too much to golf; it's just short by nature.

void t(int[]s){for(int i=s.length,t,x;i>0;t=s[x*=Math.random()],s[x]=s[i],s[i]=t)x=i--;}

With some line breaks:

void t(int[]s){
    for(int i=s.length,t,x;
        i>0;
        t=s[x*=Math.random()],
        s[x]=s[i],
        s[i]=t
    )
        x=i--;
}

This shuffles in place, modifying the original array s[]. Test program:

public class Shuffle {
    public static void main(String[] args) {
        int[] a = {1,2,3,4,5,6,7,8,9};
        new Shuffle().t(a);
        for(int b:a)
            System.out.print(b+" ");
    }
    void t(int[]s){for(int i=s.length,t,x;i>0;t=s[x*=Math.random()],s[x]=s[i],s[i]=t)x=i--;}
}

Geobits

Posted 2015-02-03T14:13:38.343

Reputation: 19 061

1No, the challenge states that you can assume that it "is perfectly uniform over the requested range". The requested range of Math.random() has a size which is a power of two, so this doesn't meet spec. – Peter Taylor – 2015-02-03T15:52:02.740

@Peter I'm not sure I agree. The docs say the range is [0.0 - 1.0]. Whether that can be represented perfectly by a FP number doesn't matter if I can assume it's perfectly uniform over that range. – Geobits – 2015-02-03T15:56:10.403

@PeterTaylor "approximately" only means "up to the issues inherent to PRNGs in general". The range here is [0.0..1.0], otherwise this would have been accessing out of the bounds. – John Dvorak – 2015-02-03T15:58:29.997

@PeterTaylor unless you read the rule as "you may assume the PRNG generates floats with probability perfectly proportional to their density, but you may not assume that floats are an accurate representation of the real line", which would be unfair to languages that use floating point randomness as their source of perfectly random indexes. – John Dvorak – 2015-02-03T16:01:37.183

1@PeterTaylor Jan's and Geobits' interpretations are indeed how I intended the rule - that you don't have to worry about the actual cycle-length of your PRNG. – Martin Ender – 2015-02-03T16:02:08.907

1@MartinBüttner the cycle length is not the issue here - that is covered by your rule. The coarseness of floats is. – John Dvorak – 2015-02-03T16:05:01.033

@JanDvorak, actually it doesn't generate floats with probability proportional to their density, or you'd be much more likely to get a number less than 0.5 than a number greater than 0.5. But it's selecting (approximately) uniformly from a finite set of doubles, not an uncountable set of reals. – Peter Taylor – 2015-02-03T16:05:41.303

@PeterTaylor by "proportional to their density" I meant inverse proportionality. As in, 0.6 has its ULP twice as big as 0.3, so it should be twice as likely to occur. – John Dvorak – 2015-02-03T16:09:58.837

Getting this distribution out of a perfect bit source might be an interesting challenge, actually. – John Dvorak – 2015-02-03T16:10:45.320

Wow... Almost as short as a python solution. – TheNumberOne – 2015-02-03T17:58:52.367

3@TheBestOne It's one byte shorter than the only currently-posted python solution ;) – Geobits – 2015-02-03T18:00:24.173

1Not any more! :D – Sp3000 – 2015-02-04T00:03:51.660

1@Sp3000 Your turn ;) – Geobits – 2015-02-04T03:35:39.950

Annoyingly, a C# clone of this requires 5 more characters. (You need a new Random() and it's cheaper to assign Next(i) to x and shuffle the increments around than to call NextDouble().) – Rawling – 2015-02-04T12:16:39.393

Can't you replace s[i]=t)x=i--; with s[x=--i]=t); to reduce 1 byte? – Ismael Miguel – 2015-03-12T16:14:23.667

@IsmaelMiguel Not really. x=i-- needs to be executed first in the loop or else it's undefined for the first iteration. – Geobits – 2015-03-12T16:17:14.400

But you have int i=s.length right inside the for loop. – Ismael Miguel – 2015-03-12T16:19:16.920

@IsmaelMiguel No, I mean x is undefined. You can try it if you want, but simply moving it breaks the program. – Geobits – 2015-03-12T16:21:09.413

For some reason I find that extremely weird. I have no way to test it now (maybe ideone, but I'm not very familiar with Java). Nor knowledge. But I still find it weird since you have s[x*=Math.random()] and that runs fine. – Ismael Miguel – 2015-03-12T16:29:33.717

@IsmaelMiguel x=i-- is run before x*=Math.random() due to the loop structure. If I move it, then it comes after and x is undefined the first time it tries to multiply. – Geobits – 2015-03-12T16:33:21.627

1Now I get it. Still find it weird, but I get it. Thanks a lot for the explanation. Dang, I had my hopes high! – Ismael Miguel – 2015-03-12T16:42:18.443

8

Python 2, 86 bytes

from random import*
def S(L):i=len(L);exec"i-=1;j=randint(0,i);L[i],L[j]=L[j],L[i];"*i

This is a function which shuffles the array in place without returning it, using a straightforward implementation of the Fisher-Yates shuffle. Getting random numbers from Python is expensive...

Thanks to @xnor and @colevk for tips.

Sp3000

Posted 2015-02-03T14:13:38.343

Reputation: 58 729

That range expression looks pretty cumbersome. Surely it's shorter to count down manually as while i:i-=1;...? – xnor – 2015-02-03T17:14:33.433

@xnor Yeah it is - thanks for that. I keep forgetting that while tends to be shorter than for for this sort of thing... – Sp3000 – 2015-02-03T21:54:11.533

1Awww... now my Java answer isn't beating this. I was quite happy for a very short while :( – Geobits – 2015-02-03T23:56:26.433

You can save another 2 bytes by making i=len(L) and putting the decrement at the beginning of the while loop. – colevk – 2015-02-04T02:45:14.977

8

J, 45 44 characters

This was a tricky one.

<@({.,?@#@}.({,<^:3@[{])}.)&>/@(<"0@i.@#,<)

Here is an explanation:

  1. # y: The tally of y, that is, the number of elements in y.
  2. ?@# y: A random number uniformly distributed over the range from 1 to (#y)-1.
  3. x { y: The item from y at index x.
  4. (<<<x) { y: All items except the item at index x in y.
  5. x , y: y appended to x.
  6. x ({ , <^:3@[ { ]) y: The item at index x in y, then all the other items.
  7. (?@# ({ , <^:3@[ { ]) ]) y A random it from y, then all the other items.
  8. x {. y: The first x items taken from y.
  9. x }. y: The first x items dropped from y.
  10. x ({. , }.) y: The first x items taken from y, then the first x items dropped from y
  11. x ({. , (?@# ({ , <^:3@[ { ]) ])@}.) y: The first x items taken from y, then the first x items from y processed as in number 7.
  12. x ({. , ?@#@}. ({ , <^:3@[ { ]) }.) y: The same thing with the drop pulled in to save one character.
  13. u/ y: u inserted between the items of y.
  14. < y: y boxed.
  15. <"0 y: Each item of y boxed.
  16. i. y: integers from 0 to y - 1.
  17. i.@# y: integers from 0 to (#y) - 1.
  18. (<"0@i.@# , <) y: Integers from 0 to (#y) - 1 each boxed and then y in a single box. This is needed because arrays in J are uniform. A box hides the shape of its content.
  19. x u&v y: like (v x) u (v y).
  20. > y: y opened, that is, without its box.
  21. x ({. , ?@#@}. ({ , <^:3@[ { ]) }.)&> y the phrase from number 12 applied to its unboxed arguments.
  22. ({. , ?@#@}. ({ , <^:3@[ { ]) }.)&>/ y the phrase from number 21 inserted between items of y.
  23. ({. , ?@#@}. ({ , <^:3@[ { ]) }.)&>/@(<"0@i.@# , <) y the phrase from number 22 applied to the the result of the phrase from number 18, or, a uniform permutation of the items of y.

FUZxxl

Posted 2015-02-03T14:13:38.343

Reputation: 9 656

1I just can't distinguish all the parentheses. And that triple boxing <@<@<@[ is also a mystery... Waiting for explanation. :) – randomra – 2015-02-03T16:08:05.633

2Once this gets explained, I might be much more likely to upvote this answer ;-) – John Dvorak – 2015-02-03T16:12:12.783

@randomra Here you go. – FUZxxl – 2015-02-03T16:25:07.693

@JanDvorak Is the explanation satisfying? – FUZxxl – 2015-02-03T16:30:20.503

Great explanation! I didn't know about all the boxed use of from ({). And I really like the &>/ trick to manipulate a list. I'm sure I could have used it a couple times before. – randomra – 2015-02-03T16:49:32.367

Is this really O(n)? If the lists are arrays and not linked lists some of these operations take O(n^2) total time (O(n) used n times) like step 4 and 10. (I could easily be wrong just asking.) – randomra – 2015-02-04T23:25:45.570

@randomra That's my fear, too. J has optimized code for many common things though, so it might be O(n), it might also be O(n²). I'm not really sure. – FUZxxl – 2015-02-05T00:53:10.033

@FUZxxl I believe the fear is correct. I made a comment to the main post stating that your solution and aditsu's CJam solution both unfortunately get knocked down to O(n²) due to list operations that actually take O(n), which I confirmed with timed tests. Waiting for OP to comment on the matter. – Runer112 – 2015-02-05T13:53:40.603

@Runer112 You did actually time this? In that case, I'm afraid this is indeed invalid. – Martin Ender – 2015-02-05T18:00:59.463

@MartinBüttner Yes, I timed it. I expressed this concern earlier as a comment to the original post, which also mentions aditsu's CJam solution as having a similar problem (which I also timed). – Runer112 – 2015-02-05T18:09:03.687

@Runer112 Yes, I left a comment regarding this on aditsu's answer. Thanks for pointing it out. – Martin Ender – 2015-02-05T18:09:45.460

5

Pyth, 25 bytes

Test it here.

Yet another Fisher-Yates implementation. Is essentially the same as @Sp3000 python solution, just in pyth.

FNrlQ1KONJ@QN XXQN@QKKJ)Q

Thanks to @Jakube for the swapping trick

<implicit>    Q=input()
FNrlQ1        For N in len(Q) to 1, only goes len Q-1 because how range implemented in pyth
 KON          K = random int 0-N
 J@QN         J=Q[N]
 <space>      Suppress print
 XXQN@QKKJ    Swap K and J
)             End for
Q             Print Q

Maltysen

Posted 2015-02-03T14:13:38.343

Reputation: 25 023

You can save two bytes by combining those two list assignments: XXQN@QKKJ instead of XQN@QK XQKJ. – Jakube – 2015-04-07T21:24:44.457

@Jakube thanks for the tip. I knew there must have been a way to swap values in a list, and this is really smart. You should add it to the tips list. – Maltysen – 2015-04-07T21:35:07.183

4

Perl, 68 56 44

Like many other solutions, this uses the Fisher-Yates algorithm.

Using nutki's comment, 12 characters are saved by using $_ instead of $i and performing the operations in the array indices.

44:

sub f{@_[$_,$j]=@_[$j=rand$_,--$_]for 1..@_}

56:

sub f{$i=@_;$j=int(rand$i),@_[$i,$j]=@_[$j,$i]while$i--}

This is my first codegolf.

Bonsaigin

Posted 2015-02-03T14:13:38.343

Reputation: 51

Not a bad start, I did not know that you can use @_[...] as rvalue like that. Can be golfed further into sub f{@_[$_,$j]=@_[$j=rand$_,--$_]for 1..@_}. – nutki – 2015-02-06T11:32:46.580

3

Octave, 88 77 bytes

function s=r(s)for(i=length(s):-1:1)t=s(x=randi(i));s(x)=s(i);s(i)=t;end;end

Yet another Fisher-Yates implementation... Should be fairly straightforward if I add the usual line returns and spacing:

function s=r(s)
  for(i=length(s):-1:1) # Counting down from i to 1
    t=s(x=randi(i));    # randi is builtin number generator for an int from 0 to i
    s(x)=s(i);
    s(i)=t;
  end
end

The "end" keywords really kill the golf score here, unfortunately. Hey, I can use "end" instead of "endfor" and "endfunction"!

dcsohl

Posted 2015-02-03T14:13:38.343

Reputation: 641

1Just FYI, the "bytes" isn't really required by the code, it just makes sure there is a headline, which contains a comma (to separate the language) and at least one number after the comma, and then just chooses the last number that isn't crossed out. Having "bytes" in there is still nice though. ;) – Martin Ender – 2015-02-06T19:11:20.950

1You could save 1 byte by using numel instead of lenght. As a bonus your program would also work with 2-D arrays aka matrices ;) – paul.oderso – 2016-08-17T13:46:27.963

3

C, 63 61 60 bytes

i,t;s(a,m)int*a;{for(;m;a[m]=t)t=a[i=rand()%m--],a[i]=a[m];}

Just a straight implementation of Fischer-Yates that sorts the given array in place. Compiles and links perfectly fine with the visual studio compiler (vs2013, haven't tested the other versions) and the Intel Compiler. Nice looking function signature is s(int array[], int length). I'm legitimately impressed I beat Python and Ruby.

This does assume srand() is called and rand() is implemented properly, but I believe this rule allows for that:

You may assume that any built-in random number method runs in O(1) and is perfectly uniform over the requested interval

Nicely formatted version:

index, temp;
shuffle(array, length) int* array;  {
    for(;length; array[index] = temp)
        index = rand() % length--,
        temp = array[length],
        array[length] = array[index];
}

pseudonym117

Posted 2015-02-03T14:13:38.343

Reputation: 1 053

I think it suffices to make the function header s(a,m)*a{, but I'm not sure and don't want to test either. You might want to do a xor-swap, like in a[i]^=a[m]^=a[i]^=a[m]. This also avoids the need to declare t. – FUZxxl – 2015-02-03T22:03:15.053

@FUZxxl I believe an xor swap causes problems if i==m. – Geobits – 2015-02-03T22:38:02.790

@Geobits indeed. I missed that possibility. – FUZxxl – 2015-02-03T22:40:14.343

I was just trying to figure out why that wasn't working... should have remembered that. Also I do need s(a,m)int*a for visual studio and the intel compiler. Don't have gcc or clang installed to test, but I assume they will also complain. – pseudonym117 – 2015-02-03T22:43:13.387

This is pretty impressively golfed. After trying a lot of modifications that didn't save anything, I did manage to see a way to save 2 characters. If you change the swap order so that the first swap statement becomes t=a[i], you can then move the i=rand()%m-- statement inside as the array index. – Runer112 – 2015-02-04T18:17:56.943

I copied into VS2013 and turned off warnings...still there are 12 errors. No variable declarations and variables before '{' etc. – bacchusbeale – 2015-02-05T17:15:36.427

its probably compiling it as c++ code, which is stricter than c. compile it from a VS developer command prompt using cl. also be sure the file is .c, not .cpp – pseudonym117 – 2015-02-05T17:25:49.447

You can remove 1 byte by transforming for(;m;a,b,c); into for(;m;c)a,b; – anatolyg – 2015-02-10T22:12:46.443

2

MATL, 16 bytes

XH`HnYr&)XHxvHHn

Try it online!

Fisher-Yates in MATL. Almost a third of this program is devoted to the letter H, which corresponds to the clipboard function in MATL.

Basically, H stores the unused items from the input, while the stack keeps track of the shuffled list.

Sanchises

Posted 2015-02-03T14:13:38.343

Reputation: 8 530

2

Japt, 12

rÈiMqZÄ Y}[]

Try it!

-10 (about half ;) thanks to @Shaggy!

I have been wanting to try out a golfing language, and the Japt interpreter had good documentation and a way to try things out in the browser.

Below is the strategy I took:

  • Reduce input seeding with an empty array
  • At each step, find a random slot to insert the current element

dana

Posted 2015-02-03T14:13:38.343

Reputation: 2 541

1

Welcome to Japt, good to have you with us. I think this works for 9 bytes, using the same method. If the RNG isn't satisfactory, though, then try this instead.

– Shaggy – 2019-01-20T17:58:37.917

@Shaggy - Thanks for the tips! :) I ended up using a slightly modified version of your 2nd solution. Since the 3rd parameter of the reduce function is an index, we already know the length. – dana – 2019-01-20T18:34:49.953

2

Ruby, 57 bytes

->a{a.size.times{|i|j=rand(i+1);a[i],a[j]=a[j],a[i]};p a}

Input (as lambda function):

f.([1,2,3,4,5])

Output:

[2, 1, 4, 3, 5]

Zero Fiber

Posted 2015-02-03T14:13:38.343

Reputation: 640

2

Java 8, 77

(x)->{for(int i=x.length,j,t;;t=x[j*=Math.random()],x[j]=x[i],x[i]=t)j=i--;};

It's a lambda taking int[] and returning void. My first attempt seemed not very interesting, so I decided to have it exit by throwing an exception.

Test program:

interface shuff {
    void shuff(int[] x);
}
class Ideone
{
    public static void main (String[] args) throws java.lang.Exception
    {
        shuff s = (x)->{for(int i=x.length,j,t;;t=x[j*=Math.random()],x[j]=x[i],x[i]=t)j=i--;};
        int[] x = {3, 9, 2, 93, 32, 39, 4, 5, 5, 5, 6, 0};
        try {
            s.shuff(x);
        } catch(ArrayIndexOutOfBoundsException _) {}
        for(int a:x) System.out.println(a);
    }
}

feersum

Posted 2015-02-03T14:13:38.343

Reputation: 29 566

1Isn't it cheating to use a lambda to get around having to write a function signature, when you have to supply a delegate in order to use the lambda anywhere? Also... can't you drop the parentheses around Math.random()? – Rawling – 2015-02-04T14:37:34.470

1

@Rawling You could vote in this meta question. Currently, there are 9 votes in favor of lambdas, and 0 against. Yes, the parentheses can be removed.

– feersum – 2015-02-04T19:52:16.043

Huh, if there's a meta post and a so-far-consensus then fire away. (And enjoy the two-lower golf score on me :p) – Rawling – 2015-02-04T22:15:49.807

3I think, it's unfair for function to stop by exception in a normal case, is it? – Qwertiy – 2015-02-04T23:34:18.800

1@Qwertiy To each his own... You think it's unfair, I think it's great. – feersum – 2015-02-04T23:36:55.940

Does the x need to be wrapped in parentheses? – Khuldraeseth na'Barya – 2018-03-23T20:55:46.950

Instead of shuff interface, you can use predefined java.util.function.Consumer<int[]> functional interface. – Konrad Borowski – 2018-04-04T07:47:33.020

2

Golflua, 37

How to run Golflua?

~@i=1,#X`r=M.r(i)X[i],X[r]=X[r],X[i]$

The input is provided as a table in the variable X. The table is shuffled in place.

Example usage:

> X={0,-45,8,11,2}
> ~@i=1,#X`r=M.r(i)X[i],X[r]=X[r],X[i]$
> w(T.u(X))
-45 0 8 11 2

mniip

Posted 2015-02-03T14:13:38.343

Reputation: 9 396

2

R, 79 bytes

f=function(x){n=length(x);for(i in 1:n){j=sample(i:n,1);x[c(i,j)]=x[c(j,i)]};x}

This is a straightforward implementation of the Fisher-Yates shuffle. The R function sample draws a simple random sample of a given size from a given vector with equal probability. Here we're drawing a random sample of size 1 at each iteration from the integers i, ..., n. As stated in the question, this can be assumed to be O(1), so in all this implementation should be O(N).

Alex A.

Posted 2015-02-03T14:13:38.343

Reputation: 23 761

2

Mathematica, 82 90 83 93 bytes

Note: This variation the Fisher-Yates shuffle is actually Martin Büttner's solution, with some code paring by alephalpha. s is the input array. Nothing fancy-smancy, but sometimes the simple things are the most elusive.

f@s_:=(a=s;m=Length@a;Do[t=a[[r=RandomInteger@{1,m-1}]];a[[r]]=a[[m]]; a[[m]]=t,{n,1,m-1}];a)

DavidC

Posted 2015-02-03T14:13:38.343

Reputation: 24 524

You can use Do here. It's shorter than While. – alephalpha – 2015-02-07T10:36:46.660

2

Matlab, 67

Also implementing Fisher-Yates.

a=input('');n=numel(a);for i=1:n;k=randi(i);a([i,k])=a([k,i]);end;a

I thought it was too bad I could not use Matlab's randperm function. But after some fiddling around, I thought I may look at the source of randperm to see how it is done, and I was astonished to see that there was just one line: [~,p] = sort(rand(1,n)) =)

flawr

Posted 2015-02-03T14:13:38.343

Reputation: 40 560

2

Perl, 44

sub f{($_[$x],$_)=($_,$_[$x=rand++$i])for@_}

Another perl in 44 characters. Example use:

@x=(1..9);f(@x);print@x

nutki

Posted 2015-02-03T14:13:38.343

Reputation: 3 634

2

TI-BASIC, 46 bytes

For(X,dim(L1),2,-1:randInt(1,X→Y:L1(X→Z:L1(Y→L1(X:Z→L1(Y:L1

1   111   2  1111112       1111112 111112 1112 111112 1112

Source for byte count

Ypnypn

Posted 2015-02-03T14:13:38.343

Reputation: 10 485

1You're missing the End. – lirtosiast – 2015-09-30T07:05:33.567

2

K, 31 chars

f:{{l[i:x,1?x]:l@|i}'|!#l::x;l}

Not quite as short as the one I put up before (which got disqualified)...oh well.

It's a basic Fisher-Yates shuffle. This was built with lots of help from the Kona mailing list.

kirbyfan64sos

Posted 2015-02-03T14:13:38.343

Reputation: 8 730

2

JavaScript (ES6), 66

This function shuffles the array in place. It also returns a byproduct array that is NOT the shuffled output and must not be considered.

F=a=>a.map((v,i)=>a[a[i]=a[j=0|i+Math.random()*(a.length-i)],j]=v)

edc65

Posted 2015-02-03T14:13:38.343

Reputation: 31 086

1

Perl, 41 bytes

sub f{push@b,splice@_,rand@_,1while@_;@b}

Try it online!

Xcali

Posted 2015-02-03T14:13:38.343

Reputation: 7 671

1

PowerShell, 39 27 bytes

-4 bytes thanks to @mazzy

$args-split','|sort{random}

Accepts input as commandline arguments, and outputs as an array.

Gabriel Mills

Posted 2015-02-03T14:13:38.343

Reputation: 778

Welcome! You can use random only. https://codegolf.stackexchange.com/a/778/80745

– mazzy – 2018-10-26T16:34:35.933

1

STATA, 161

di _r(s)
set ob wordcount($s)
token $s
g a=0
foreach x in $s{
gl j=floor(runiform()*_n)+1
replace a=`$j' if word($s,_n)=`x'
replace a=`x' if word($s,_n)=`$j'
}
l

Expects input as space separated numbers. I can remove the headers and observation numbers from the output if you would like, but otherwise this is shorter.

bmarks

Posted 2015-02-03T14:13:38.343

Reputation: 2 114

What's _n in this? – Martin Ender – 2015-02-03T16:30:04.037

_n is the number of the current observation. – bmarks – 2015-02-03T16:35:02.810

1

CJam - 30

q~_,,W%{_I=I)mr:J2$=@I@tJ@t}fI

Try it at http://cjam.aditsu.net/

Example input: [10 20 30 40 50]
Example output: 3020401050 (add a p at the end of the code for pretty printing)

If the code is allowed to take the input from the stack (like a function), then the first 2 characters can be removed, reducing the size to 28.

Explanation:

The code is longer than I hoped, due to the lack of a "swap" operator for arrays
(to be implemented later :p)

q~            read and evaluate the input (let's call the array "A")
_,,           make an array [0 1 2 ... N-1] where N is the size of A
W%            reverse the array, obtaining [N-1 ... 2 1 0]
{…}fI         for I in this array
    _I=       push A[I]
    I)mr:J    push a random number from 0 to I (inclusive) and store it in J
              stack: A, A[I], J
    2$=       get A[J]
    @I@t      set A[I] = A[J]
              stack: former A[I], A
    J@t       set A[J] = former A[I]

aditsu quit because SE is EVIL

Posted 2015-02-03T14:13:38.343

Reputation: 22 326

As mentioned in the comments, I'm afraid this is invalid. At the very least _ is O(N) (inside an O(N) loop). Unfortunately, I don't see a way to work around that in CJam. – Martin Ender – 2015-02-05T17:58:52.213

Lists are handled like immutable objects, so duplication is just implemented as duplicating the reference. It's actually the t that kills it, as it can't mutate the list and now must create a copy. – Runer112 – 2015-02-05T18:18:31.057

@MartinBüttner I was about to post the same thing as Runer112; yes there might be a problem with t, I'd like to improve it in future versions.. – aditsu quit because SE is EVIL – 2015-02-05T18:20:07.473

So this code follows the spirit of the question, but not the "letter", due to internal language implementation issues. – aditsu quit because SE is EVIL – 2015-02-05T18:22:06.577

1

SQF, 91 bytes

params["i"];{n=floor random count i;i set[_forEachIndex,i select n];i set[n,_x]}forEach i;i

Οurous

Posted 2015-02-03T14:13:38.343

Reputation: 7 916

1This is biased (see "swap (i <-> random)" on Will It Shuffle), but you can turn it into Fisher-Yates (which is unbiased) by replacing %x with %i. – Martin Ender – 2015-02-04T09:53:06.207

1

Pyth, 27 bytes

Test it here

FkQJOhlYaY?@YtJJkIJ XYtJk;Y

This is an implementation of the incremental Fisher-Yates shuffle, mentioned second here.

isaacg

Posted 2015-02-03T14:13:38.343

Reputation: 39 268

1

Javascript ES6, 69

a=>{m=a.length;while(m)[a[m],a[i]]=[a[i=~~(Math.random()*m--)],a[m]]}

It's Fisher–Yates.

PS: Can be tested in Firefox

Qwertiy

Posted 2015-02-03T14:13:38.343

Reputation: 2 697

@MartinBüttner, removed it :) – Qwertiy – 2015-02-04T23:30:09.253

1

Haskell, 170

import System.Random
import Data.Array.IO
s a=do(_,n)<-getBounds a;sequence$map(\i->do j<-randomRIO(i,n);p<-a%i;q<-a%j;writeArray a j p;return q)[1..n]where(%)=readArray

Another Fisher-Yates solution inspired by the algorithm at https://wiki.haskell.org/Random_shuffle.

s is a function which has signature: IOArray Int a -> IO [a]

Jmac

Posted 2015-02-03T14:13:38.343

Reputation: 111

1

JavaScript (ES 6), 61

S=a=>(a.map((c,i)=>(a[i]=a[j=Math.random()*++i|0],a[j]=c)),a)

You can test it here by just adding a line that says shuffle = S (Firefox only).

core1024

Posted 2015-02-03T14:13:38.343

Reputation: 1 811

1

Java, 93 bytes

a->{for(int b=0,c,d=0,e=a.length;b<e;c=a[b],a[b]=a[d],a[d]=c,b++,d=b)d+=Math.random()*(e-b);}

Example usage: http://ideone.com/RqSMnZ

TheNumberOne

Posted 2015-02-03T14:13:38.343

Reputation: 10 855

0

Julia 0.6, 56 bytes

!a=for i=length(a):-1:1;j=rand(1:i);a[[i,j]]=a[[j,i]]end

Try it online!

Fisher-Yates.

a[[i,j]]=a[[j,i]] is slightly shorter than a[i],a[j]=a[j],a[i].

rand(1:i) samples from the range 1:i.

LukeS

Posted 2015-02-03T14:13:38.343

Reputation: 421

0

SmileBASIC, 56 bytes

Fisher-Yates algorithm of course.

DEF S A
FOR I=1-LEN(A)TO-1SWAP A[-I],A[RND(1-I)]NEXT
END

Downwards FOR loops are expensive (STEP -1), so instead you can just negate the start/end values, which only adds 1 extra character. This is the code if FOR implicitly went backwards when the end value is lower than the start:

DEF S A
FOR I=LEN(A)-1TO 1SWAP A[I],A[RND(I+1)]NEXT '1 character less
END

12Me21

Posted 2015-02-03T14:13:38.343

Reputation: 6 110

0

Jolf, 46 bytes

Invalid, since language postdates question. Is otherwise a perfectly valid answer. Try it ici!

v'nlKW«n)v'HC*mrhntv'S.Kn$K[n]=K[H];K[H]=S$}K

Explanation

v'nlKW«n)v'HC*mrhntv'S.Kn$K[n]=K[H];K[H]=S$}K
                                              implicit: K = input array
v'n                                           set n to
   lK                                           the length of K
     W«n)                                     while(--n){
         v'H                                    set H to
            C     t                               the integer part of
             *mr                                  Math.random() times
                hn                                  n+1
                   v'S                          set S to
                      .Kn                         the nth member of K
                         $K[n]=K[H];K[H]=S$     eval as javascript (perform swap)
                                           }  }
                                            K K
                                              implicit: print K

This runs in O(n) time, I believe, as n is strictly decreasing.

I used this as the basis for the code

Conor O'Brien

Posted 2015-02-03T14:13:38.343

Reputation: 36 228

-1

VBA/Basic, 96

Someday I will find a good challenge for vba or basic, but not today

Fisher-Yates

Sub s(o(), n)
For i = 0 To n
r = Int(Rnd() * (n + 1))
x = o(r)
o(r) = o(i)
o(i) = x
Next
End Sub

dwana

Posted 2015-02-03T14:13:38.343

Reputation: 531

This is biased. It's what Will it Shuffle calls "swap (i <-> random)". You can turn it into actual Fisher-Yates by replacing n + 1 with i + though. – Martin Ender – 2015-02-04T15:30:00.550

ty, but damm then I need to add 'step -1' – dwana – 2015-02-04T15:48:08.437

Sorry, I don't know what you mean. – Martin Ender – 2015-02-04T15:49:59.467