如何按每个字符索引交替使用传入的字符串?

时间:2015-02-27 19:10:33

标签: ruby arrays string multidimensional-array

我遇到了一个关于Codewars问题的奇怪事情。以下是说明:

  

写一个函数toWeirdCase(Ruby中的怪异)接受一个字符串,并返回相同的字符串,每个单词大写字母中包含所有偶数索引字符,并且每个单词中的所有奇数索引字符都更低。刚解释的索引是基于零的,所以零第i个索引是偶数,因此该字符应该是大写的。

     

传入的字符串只包含字母字符和空格('')。只有在有多个单词时才会出现空格。单词将由单个空格分隔('')。   例子:

weirdcase( "String" )#=> returns "StRiNg"
weirdcase( "Weird string case" );#=> returns "WeIrD StRiNg CaSe"

这是我的代码:

def weirdcase string

  @case = []

# Ternary:
  string.each_char { |c|
#    string.index(c).even? ? @case.push(c.upcase) : @case.push(c.downcase)
    c =~ /[[:alpha:]]/ ? (string.index(c).even? ? (@case.push(c.upcase)) : (@case.push(c.downcase))) : (string.index(c) + 1)
    }

# If/Then:
#  string.each_char { |c|
    #if string.index(c).even? && c != " " 
#    if c =~ /[[:alpha:]]/ && string.index(c).even?
#    then @case.push(c.upcase)
#    else @case.push(c.downcase)
#    end  }

  @case.join

end
p "TEST"
p weirdcase "this is a test"
p weirdcase "thisisatest"
p weirdcase " th is  is  a  t es t"

结果:

"TEST"
"ThIsIsATesT"
"ThIsIsATEsT"
"tHIsIsAtest"
weirdcase
should return the correct value for multiple words
Expected: "ThIs Is A TeSt", instead got: "ThIsIsATesT"
0 Passed
1 Failed
0 Errors

Process took 171ms to complete

以下是测试:

describe 'weirdcase' do
  #it 'should return the correct value for a single word' do
   #  Test.assert_equals(weirdcase('This'), 'ThIs');
  #  Test.assert_equals(weirdcase('is'), 'Is');
  #end
  it 'should return the correct value for multiple words' do
    Test.assert_equals(weirdcase('This is a test'), 'ThIs Is A TeSt');
  end
end

我尝试过几种不同的方式来编写这些代码,并且我不断得到相同的结果:而不是"这是一个很好的方式"结果,我得到了#34; ThIsIsATesT"或者其他一些变化,其中交替的大写似乎一旦到达单词" test"就会失败,这对我来说没有任何意义 - 它似乎违背了这些方法应该做的事情。我也在irb中尝试过,看到了相同的结果,所以我不会认为是一个Codewars错误。

我在Ruby上还是比较新的。任何人都可以帮我找到我必须忽略的事情和/或解释这个代码是如何产生这个结果的吗?

更新

每个人,谢谢你的好建议。我将标题更新为更具描述性的内容,并从头开始重新编写此代码,以单独索引迭代每个单词,而不是将其视为一个长字符串。我虽然仍然遇到麻烦。这是我的新代码:

def weirdcase string
  char = Array.new
  puts "string: #{string}"
  string.split(' ').each do |word|
    word.each_char.with_index do |c, index|
      if index.even?
        char.push(c.upcase)
      else
        char.push(c.downcase)
      end
    end
  end
  puts "char: #{char}"
  puts "char.join(''): #{char.join('')}"
  puts "char.join('space'): #{char.join(' ')}"

end

以下是结果:

weirdcase
should return the correct value for multiple words
string: This is a test
char: ["T", "h", "I", "s", "I", "s", "A", "T", "e", "S", "t"]
char.join(''): ThIsIsATeSt
char.join('space'): T h I s I s A T e S t
Expected: "ThIs Is A TeSt", instead got: nil

所以我现在遇到的麻烦就是如何在两者之间正确地连接单词,而不是你在上面看到的。我在初次拆分后正在查找正确访问数组条目的方法。但当然我会欢迎任何人可能提供的更多提示:)

3 个答案:

答案 0 :(得分:1)

我认为你的许多问题都是由这部分代码引起的:

string.index(c).even?

假设c等于'T'。然后string.index(c)将始终返回字符串中第一个字母T的索引,该索引始终为零,即使您尝试处理字符串后面部分中的一个T字母。

要在迭代它们时获取字符索引,这样的事情应该有效:

string.each_char.with_index do |c, index|
  if index.even?
    #...
  else
    #...
  end
end

答案 1 :(得分:1)

如另一个答案中所述,index(c)调用是当前代码的主要问题。它将返回与请求的字符串匹配的字符串中的第一个索引(区分大小写)。给定您的测试字符串"this is a test",因为第一个" t"索引0(偶数)ALL(小写)t将被大写,并且自第一个" s"索引3(奇数)ALL(小写)s&s 39将是小写的。也就是说,看起来你可能会略微误读问题的一部分:

  

所有偶数索引的字符在每个单词大写字母中,并且所有奇数索引字符在每个单词中小写。

在他们的例子中,他们给你这个

weirdcase( "Weird string case" );#=> returns "WeIrD StRiNg CaSe"

如果仔细观察,基于该示例,对于多字符串,它不是基于字符串中的绝对索引,而是基于每个单词中每个字母的索引。如果是前者,则会看到此转换(e =偶数索引,o =奇数索引)

 eoeoeoeoeoeoeoeoe
"Weird string case" # => WeIrD StRiNg cAsE

因为" c"如果是一个奇数索引,所以它会小写。但是从它们的例子来看,它是大写的 - 每个单词都被视为单词中的第一个字母是该单词的索引0。

我建议a)编写一个方法,将字符串应用于字符串中的每个单词,b)将字符串拆分为单词,并使用您刚编写的方法单独应用每个单词,并c)将它们连接起来一起(不要忘记指定加入他们的角色,例如join(' ')

答案 2 :(得分:1)

工作解决方案:

经过多次试验和错误,我设法将一些有效的东西放在一起:

def weirdcase string
  arr, char, result = [],[],[]
  arr = string.split(' ').each_slice(string.split(' ').count).to_a.transpose
  arr.each_with_index do |arr_word, index|   
    arr_word.each_with_index do |word, sub_index| 
      word.each_char.with_index do |letter, letter_index| 
        letter_index.even? ? char.push(letter.upcase) : char.push(letter.downcase)
      end
    end
    result.push(char.join(''))
    char.clear
  end
  result.join(' ')
end

它很笨重,可能效率不高,但它有效。我必须:

  1. 以一种为每个单词创建子数组的方式将字符串拆分为“arr”数组,
  2. 遍历“arr”以访问单词,
  3. 对每个单词进行子迭代以访问其子数组中的字母
  4. 适当地对字母和upcase / downcase进行子迭代,
  5. 将修改后的字母一次一个地传递到“char”数组中,再次将它们连接成一个单词,
  6. 将单词传递给“result”数组,
  7. 然后清除“char”数组,这样就不会迭代地将这些单词连接在一起,如下所示:

    [ “这个”, “THISIS”, “ThIsIsA”, “ThIsIsATeSt”]

  8. 它从每次迭代的最开始开始,并且随着时间的推移将所有单词粘在一起。这是最难弄清楚的部分。我使用了很多put语句来进行错误检查,并且在我弄清楚它之前不得不进行大量的反复试验。我想有一种方法可以让它从一个数组元素移动到下一个数组元素,而不是每次都从头开始,但出于挫折感,我使用'char.clear'作为解决方法。就像我说的那样,它很笨重。拥有3个嵌套的'do'语句或3个独立的数组似乎也没有效率。任何人都可以提出任何建议,使代码更有效和/或更多Ruby-ish?

    如果我能想出一个改进的版本,我会在这里添加它。如果你很好奇,这里是Codewars-Submit-Test结果:

    weirdcase
    should return the correct value for a single word
    Test Passed: Value == "ThIs"
    Test Passed: Value == "Is"
    Test Passed: Value == "A"
    Test Passed: Value == "TeSt"
    Test Passed: Value == "LoOkS"
    Test Passed: Value == "LiKe"
    Test Passed: Value == "YoU"
    Test Passed: Value == "PaSsEd"
    should return the correct value for multiple words
    Test Passed: Value == "ThIs Is A TeSt"
    Test Passed: Value == "LoOkS LiKe YoU PaSsEd"
    Test Passed: Value == "ThIs Is ThE FiNaL TeSt CaSe"
    Test Passed: Value == "JuSt KiDdInG"
    Test Passed: Value == "Ok FiNe YoU ArE DoNe NoW"