How to shuffle characters in a string without using Collections.shuffle(…)?

后端 未结 14 2182
南旧
南旧 2020-11-27 07:19

How do I shuffle the characters in a string (e.g. hello could be ehlol or lleoh or ...). I don\'t want to use the Collections.shuffle(...) method, is there anyt

相关标签:
14条回答
  • 2020-11-27 08:08

    Not sure why you wouldn't want to use shuffle, unless it's for school. ;)

    And if you're concerned with performance, you definitely can't use any solution that concatenates strings with "+".

    Here's the most compact solution I could come up with:

    public static String shuffle(String string) {
        if (StringUtils.isBlank(string) {
            return string;
        }
    
        final List<Character> randomChars = new ArrayList<>();
        CollectionUtils.addAll(randomChars, ArrayUtils.toObject(string.toCharArray()));
        Collections.shuffle(randomChars);
        return StringUtils.join(randomChars, "");
    }
    
    0 讨论(0)
  • 2020-11-27 08:10

    E.g.:

    static String shuffle(String text){
        if (text.length()<=1)
            return text;
    
        int split=text.length()/2;
    
        String temp1=shuffle(text.substring(0,split));
        String temp2=shuffle(text.substring(split));
    
        if (Math.random() > 0.5) 
            return temp1 + temp2;
        else 
            return temp2 + temp1;
    }    
    
    0 讨论(0)
  • 2020-11-27 08:12

    If you still want to restore the original String later on, try something like this:

    public static class ShuffledString
    {
        private List<Integer> indices;
        private String string;
    
        public ShuffledString(List<Integer> indices, String string)
        {
            this.indices = indices;
            this.string = string;
        }
    
        public List<Integer> getIndices()
        {
            return indices;
        }
    
        public String getRegularString()
        {
            StringBuilder stringBuilder = new StringBuilder();
    
            for (int stringIndex = 0; stringIndex < indices.size(); stringIndex++)
            {
                int characterIndex = indices.indexOf(stringIndex);
                stringBuilder.append(string.charAt(characterIndex));
            }
    
            return stringBuilder.toString();
        }
    }
    
    public static ShuffledString shuffle(String input)
    {
        List<Integer> indices = new ArrayList<>();
    
        StringBuilder output = new StringBuilder(input.length());
        while (indices.size() < input.length())
        {
            int randomIndex;
    
            while (indices.contains(randomIndex = (int) (Math.random() * input.length())))
            {
    
            }
    
            indices.add(randomIndex);
            output.append(input.charAt(randomIndex));
        }
    
        return new ShuffledString(indices, output.toString());
    }
    
    0 讨论(0)
  • 2020-11-27 08:13

    You could iterate over all the characters, comparing each one with the next. Then if Math.rand() > 0.5 swap this character with the next, otherwise move on to the next character.

    0 讨论(0)
  • 2020-11-27 08:13

    In Java 8+ this can be done using Collectors.shuffle(...) in three lines as follows:

    1. Convert the String into a List of Characters
    2. Shuffle the list
    3. Convert the shuffled List of Characters back into a String

    Code:

    public static String shuffle(final String str) {
        List<Character> chars = str.chars().mapToObj(e->(char)e).collect(Collectors.toList());
        Collections.shuffle(chars);
        return chars.stream().map(e->e.toString()).collect(Collectors.joining());
    }
    

    Demo:

    Rextester demo

    0 讨论(0)
  • 2020-11-27 08:16

    Here's code that requires neither recursion, nor converting to a Collection.

    public static String shuffle(String string) {
        StringBuilder sb = new StringBuilder(string.length());
        double rnd;
        for (char c: string.toCharArray()) {
            rnd = Math.random();
            if (rnd < 0.34)
                sb.append(c);
            else if (rnd < 0.67)
                sb.insert(sb.length() / 2, c);
            else
                sb.insert(0, c);
        }       
        return sb.toString();
    }
    
    0 讨论(0)
提交回复
热议问题