DEV Community

Daily Challenge #44 - Mexican Wave

dev.to staff on August 19, 2019

The wave (known as the Mexican wave in the English-speaking world outside North America) is an example of metachronal rhythm typically achieved in ...
Collapse
 
chrisachard profile image
Chris Achard

Got it to one line of js :)
It's a bit unreadable but... you know ๐Ÿคฃ

const wave = str => [...str].map((c, i) => `${str.slice(0, i)}${c.toUpperCase()}${str.slice(i + 1, str.length)}`)
Collapse
 
alfredosalzillo profile image
Alfredo Salzillo

Without use slice

const wave = str => [...str].filter(c => c !== ' ').map((c, i) => Object.values({ ...str, [i]: c.toUpperCase()}).join(''));
Collapse
 
chrisachard profile image
Chris Achard

oh, haha - nice!

Collapse
 
chrisachard profile image
Chris Achard

In my quest for a single line function, I missed the part about skipping the character if it's whitespace... so here's that tacked on too (though I added the filter to the end in order to keep the whole thing to one line) :)

const wave = str => [...str].map((c, i) => `${str.slice(0, i)}${c.toUpperCase()}${str.slice(i +  1, str.length)}`).filter(s => /[A-Z]/.test(s))
Collapse
 
jeddevs profile image
Theo

Always amazes me when people get it into one line. ๐Ÿ‘

Thread Thread
 
chrisachard profile image
Chris Achard

map, filter, and reduce are your friend! Whenever I'm dealing with translating one string, array, or object into another one, there's probably a way to do it by just chaining those three methods together.

Collapse
 
alvaromontoro profile image
Alvaro Montoro

CSS

This is not exactly what is requested in the challenge, but close (at least for CSS). The letters need to be wrapped on their own span, and then add "wave" to the parent element. An animation is added that transform one letter at a time into uppercase (not exactly an array, sorry, and it heavily depends on length):

@keyframes mexicanWaveText {
  0%, 20%, 100% { text-transform: lowercase; }
  10% { text-transform: uppercase; }
}

.wave span {
  text-transform: lowercase;
  animation: mexicanWaveText 11s infinite;
}

.wave span:nth-child(1n) { animation-delay: -10s; }
.wave span:nth-child(2n) { animation-delay: -9s; }
.wave span:nth-child(3n) { animation-delay: -8s; }
.wave span:nth-child(4n) { animation-delay: -7s; }
.wave span:nth-child(5n) { animation-delay: -6s; }
.wave span:nth-child(6n) { animation-delay: -5s; }
.wave span:nth-child(7n) { animation-delay: -4s; }
.wave span:nth-child(8n) { animation-delay: -3s; }
.wave span:nth-child(9n) { animation-delay: -2s; }
.wave span:nth-child(10n) { animation-delay: -1s; }
.wave span:nth-child(11n) { animation-delay: -0s; }

Here is a demo (with some other animations too):

Collapse
 
fanfan1609 profile image
Dat Vo

CSS solution is amazing :D

Collapse
 
lordapple profile image
LordApple • Edited

c++

#include <iostream>
#include <vector>

std::vector<std::string> wave(std::string str){
    std::vector<std::string> returnVal;

    for(unsigned long i = 0; i < str.size(); ++i){
        if(str[i] < 'A' || str[i] > 'z'){
            continue;
        }
        std::string copy = str;
        copy[i] -= 32;
        returnVal.push_back(copy);
    }

    return returnVal;
}

int main(){
    for(const auto& word : wave("hello world")){
        std::cout << word << std::endl;
    }

    return 0;
}
Enter fullscreen mode Exit fullscreen mode
Collapse
 
lainofthewired profile image
Lain-of-the-Wired

That's crazy.

Collapse
 
salma0110 profile image
salma0110

from where did you learn that u should use 32 , i didn't know that before
Thank you

Collapse
 
necrotechno profile image
NecroTechno

In Rust, although there is almost certainly a more efficient way of doing this.

fn main() {
    let wave = wave("hello");
    for (_i, a) in wave.into_iter().enumerate() {
        println!("{}", a)
    }
}

fn wave(input: &str) -> Vec<String> {
    let mut result = Vec::new();
    for (i, _c) in input.chars().enumerate() {
        let mut subresult = Vec::new();
        for (ind, cha) in input.chars().enumerate() {
            if i == ind {
                subresult.push(cha.to_uppercase().to_string());
            } else {
                subresult.push(cha.to_lowercase().to_string());
            }
        }
        result.push(subresult.into_iter().collect::<String>());
    }
    return result
}

Playground link here.

Collapse
 
serbuvlad profile image
ศ˜erbu Vlad Gabriel • Edited

You can use concatenation to avoid a character by character copy.

...
    for (i, c) in input.chars().enumerate() {
        let upper = c.to_uppercase().to_string();
        let subresult = input[..i].to_string() + &upper + &input[i+upper.len()..];
        result.push(subresult);
    }
...

I don't know the first thing about Rust, so this is probably not optimal either.

Playgrund link here

Collapse
 
necrotechno profile image
NecroTechno

Nice!

Collapse
 
alvaromontoro profile image
Alvaro Montoro

Funny thing. The other day I was creating a wave animation using text in CSS. It used font-weights instead of case change, but updating it to adapt to this challenge should be fairly easy. Although it wouldn't return an array, but generate an animation instead.

Collapse
 
brightone profile image
Oleksii Filonenko

Rust, with iterators:

pub fn wave(input: &str) -> Vec<String> {
    use std::iter;

    iter::repeat(input)
        .take(input.len())
        .enumerate()
        .map(|(i, part)| {
            part.chars()
                .enumerate()
                .map(|(j, c)| if i == j { c.to_ascii_uppercase() } else { c })
                .collect::<String>()
        })
        .collect::<Vec<_>>()
}
Collapse
 
jay profile image
Jay

Rust "one-liner" Playground

fn wave(s: &str) -> Vec<String> {
    (0..s.len())
        .map(|i| {
            s.chars()
                .enumerate()
                .map(|(j, c)| if j == i { c.to_ascii_uppercase() } else { c })
                .collect::<String>()
        })
        .filter(|strs| !(strs.chars().all(|c| c.is_lowercase() || c.is_whitespace())))
        .collect()
}
Collapse
 
willsmart profile image
willsmart • Edited

A little JS impl using a regex and matchAll (avail in recent browsers):

wave = crowd => [...crowd.matchAll(/[a-z]/g)].map(({0:match, input, index}) => input.substring(0,index) + match.toUpperCase() + input.substring(index+1))

Output:

> JSON.stringify(wave("go our team"),null,2)
< "[
  "Go our team",
  "gO our team",
  "go Our team",
  "go oUr team",
  "go ouR team",
  "go our Team",
  "go our tEam",
  "go our teAm",
  "go our teaM"
]"
Collapse
 
hectorpascual profile image

My python sol :

def wave(s):
    wave_list = []
    for i,c in enumerate(s):
        wave_list.append(s[:i]+c.upper()+s[i+1:])
    return wave_list

In one line with a generator and a lambda function :

wave = lambda s : [f'{s[:i]}{c.upper()}{s[i+1:]}' for i,c in enumerate(s)]
Collapse
 
jeddevs profile image
Theo

Love it

Collapse
 
thepeoplesbourgeois profile image
Josh • Edited

As an Elixir function, including documentation! And a language feature I'm writing about in an upcoming post UPDATE: the post is up!! ๐Ÿ˜ƒ

defmodule W do
  @doc ~S"""
  Takes in a string, ensures it's downcased, converts it to a charlist,
  and then processes the charlist by subtracting the proper amount from
  the `next` raw byte to arrive at the same capitalized character in the
  ASCII chart. This letter is then inserted into an iodata list in
  between the raw bytes that have already been `waved` through and the
  `rest` of the raw bytes. This iodata list is then converted back to a
  string, which is added to the head of a list of strings that represent
  the in-motion version of the wave. To finalize the in-motion wave, it
  is reversed once the input charlist has been fully processed.

  When `next` is not a lowercase letter, it is added to `waved` without
  adding a new string to `waves`.

  ## Examples

      iex>W.ave("HELLO")
      ["Hello", "hEllo", "heLlo", "helLo", "hellO"]

      iex>W.ave("hello world!")
      ["Hello world!", "hEllo world!", "heLlo world!", "helLo world!", "hellO world!",
       "hello World!", "hello wOrld!", "hello woRld!", "hello worLd!", "hello worlD!"]
  """
  def ave(string) do
    string
      |> String.downcase
      |> String.to_charlist
      |> do_wave
  end

  @ascii_upcase_val 32 # ?a - ?A

  defp do_wave(waving, waves \\ [], waved \\ '')
  defp do_wave([] = _done_waving, waves, _waved), do: Enum.reverse(waves)
  defp do_wave([next | rest], waves, waved) when next in ?a..?z do
    uppercase = next - @ascii_upcase_val
    do_wave(rest, [IO.iodata_to_binary([waved, uppercase, rest]) | waves], [waved, next])
  end
  defp do_wave([next | rest], waves, waved), do: do_wave(rest, waves, [waved, next])
end
Collapse
 
aminnairi profile image
Amin

JavaScript

function charactersIndexes(string) {
  return string.split("").reduce(function(indexes, character, index) {
    if (!/\s/.test(character)) {
      indexes.push(index);
    }

    return indexes
  }, []);
}

function upperCaseAt(index, string) {
  return string.split("").map(function(character, position) {
    if (position === index) {
      return character.toUpperCase();
    }

    return character;
  }).join("");
}

function wave(input) {
  return charactersIndexes(input).map((index) => upperCaseAt(index, input));
}

console.log(wave("hello"));
// [ 'Hello', 'hEllo', 'heLlo', 'helLo', 'hellO' ]

console.log(wave("h e l l o"));
// [ 'H e l l o', 'h E l l o', 'h e L l o', 'h e l L o', 'h e l l O' ]
Enter fullscreen mode Exit fullscreen mode

Playground

Play with it on Repl.it.

Collapse
 
ielena33 profile image
ielena

expect(received).toEqual(expected) // deep equality

- Expected  - 5
+ Received  + 5

  Array [
-   "Hello",
-   "hEllo",
-   "heLlo",
-   "helLo",
-   "hellO",
+   0,
+   1,
+   2,
+   3,
+   4,
  ]

  26 |     test("returns a mexican wave", () => {
  27 |         expect(mexicanWave("")).toEqual([]);
> 28 |         expect(mexicanWave("hello")).toEqual(["Hello", "hEllo", "heLlo", "helLo", "hellO"]);
Enter fullscreen mode Exit fullscreen mode
Collapse
 
matrossuch profile image
Mat-R-Such • Edited

Python

def wave(string):
    s=[i for i in string]
    for i in range(len(s)):
        s[i] = s[i].upper()
        yield ''.join(s)
        s = [i for i in string]

for i in wave('hello'):
    print(i)
Collapse
 
craigmc08 profile image
Craig McIlwrath • Edited
import Data.Char (toUpper, toLower) 

mexicanWave a=[[($(a!!j))(if j==i then toUpper else toLower)|j<-[0..(length a-1)]]|i<-[0..length a-1]]

One long, ugly line of haskell. (I guess 2 including the import)

Edit: missed note about skipping whitespace. Will fix it soon

Collapse
 
serbuvlad profile image
ศ˜erbu Vlad Gabriel • Edited

Go:

func mexicanWave(s string) []string {
    if !utf8.ValidString(s) {
        panic("invalid string")
    }   
    // capacity can be replaced with len(s) if iterating over
    // the string twice is a bigger problem than allocating too
    // much memory
    ss := make([]string, 0, utf8.RuneCountInString(s))
    for i, r := range s {
        u := unicode.ToUpper(r)
        ss = append(ss, s[:i] + string(u) + s[i+utf8.RuneLen(r):])
    }
    return ss
}

Play with it here.

Collapse
 
vivek97 profile image
Vivek97

JAVA

public String [] wave(String input)
{
 String [] array = new String[input.length()];

 for(int i=0; i<input.length();i++)
    {
     if(!input.substring(i,i+1).equals(" "))
        { input = input.toLowerCase();              
        array[i]= input.substring(0,i) + input.substring(i, i+1).toUpperCase()+input.substring(i+1);            
        System.out.print(array[i]+", ");
    }   
    }
 return array;  
}
Collapse
 
vivek97 profile image
Vivek97 • Edited
public void wave(String input)
{
 char[] arr = input.toCharArray();
  for(int i=0; i<arr.length;i++)
    {
     if(!(arr[i]==' '))
        {
        arr[i] = Character.toUpperCase(arr[i]);
        System.out.print(String.valueOf(arr)+", ");
        arr[i] = Character.toLowerCase(arr[i]);
       }
    }
}
Collapse
 
vivek97 profile image
Vivek97
public void wave(String input)
{
 char[] arr = input.toCharArray();
  for(int i=0; i<arr.length;i++)
    {
     if(!(arr[i]==' '))
        {
        arr[i] = Character.toUpperCase(arr[i]);
        System.out.print(String.valueOf(arr)+", ");
        arr[i] = Character.toLowerCase(arr[i]);
       }
    }
}
Collapse
 
jamespotz profile image
James Robert Rooke

In ruby

Collapse
 
jeddevs profile image
Theo

Nice, I have been having issues with repl loading up.
Not the website or even an repl page just the code within it,
getting that dreaded: Failed to connect, retrying message.
Then after about 5 minutes it loading, have you been having similar?
(sorry for being a pain)

Collapse
 
jamespotz profile image
James Robert Rooke

Sorry I haven't had that kind of issue. It's ok

Collapse
 
thepeoplesbourgeois profile image
Josh

Nice! The runtime complexity is pretty substantial, but it's a really good first pass on the problem ๐Ÿ‘

Collapse
 
hanachin profile image
Seiei Miyagi

ruby <3

def wave(s)
  s.size.times.filter_map { |i| s[i] =~ /\S/ && s.dup.tap { @1[i] = @1[i].upcase } }
end

puts wave("hello world")
Collapse
 
israelsameach profile image
sameach israel

C#

var wave = str.Select((c, i)=> str.Substring(0, i) + str.Substring(i, 1).ToUpper() + str.Substring(i+1, str.Length-i-1)).Where(s => !s.All(c => c.ToString() == c.ToString().ToLower()));