挑战很简单:


返回所提供句子中最长单词的长度。


解决方案也很简单:

function findLongestWord(str) {
  arr = str.split(' ');
  size = 0;
  for (var s in arr) {
    if (arr[s].length > size) {
      size = arr[s].length;
    }
  }
  return size;
}


但是,我隐约记得,除非绝对必要,否则您不应该在JavaScript中使用for..in。此循环更惯用的方法是什么?

评论

for(let i = 0; i size)...}?

甚至arr.sort(s => s.length)[0] .length; (按字符串长度排序,获取最短字符串,获取长度)或arr.map(s => s.length).sort()[0]; (使用arr中的字符串长度创建新数组,对该数组进行排序,以得到最短的大小)

您在使用ES6吗?

绝对可以在ES6中编写并使用Babel进行转换。生产率提高太有价值了。

@NickUdell标点符号被视为挑战中单词的一部分。

#1 楼

首先,由于您不是在寻找最长的单词,而是最长的单词的长度,所以我不将函数命名为findLongestWord。请改尝试getLongestWordLength

您忘记了var的变量。这使得它们到达了全局范围并在此处声明,我们不希望这种情况发生。对于ES6,还有let

for-in仅在对象上建议,甚至在用hasOwnProperty保护的对象上也建议。那是因为它遍历了原型属性(除了数组元素或实例属性以外的其他内容)。一个规则循环(forwhile),同时增加索引直到长度更好。但是,还有一种更好的方法...

您可以通过在拆分字符串上使用map来创建长度映射,并返回字符串的长度。然后,使用Math.max获取长度数组中的最大数字。我们可以使用扩展运算符(...)将数组扩展为Math.max的参数。

function getLongestWordLength(str){
  return Math.max(...(str.split(' ').map(s => s.length)));
}


以上是ES6语法。等效于ES5的外观如下所示。除了更为冗长的map以外,还有一个显着差异是使用applyMath.max提供了一组动态的参数。




 function getLongestWordLength(str) {
    return Math.max.apply(Math, str.split(' ').map(function (s) {
        return s.length;
    }));
}

document.write(getLongestWordLength('The quick brown fox jumps over the lazy doge')); 




评论


\ $ \ begingroup \ $
这看起来很惯用,是的。无论如何,不​​要迭代我们不感兴趣的信息是有意义的。好答案!
\ $ \ endgroup \ $
–桅杆
2015年12月23日下午0:31

#2 楼

现在更新/编辑,不再只用手机,我要添加更多内容,并说明“为什么/如何使用Array.prototype.reduce。 br />
 someString.split(' ')
  .reduce((max, word) => word.length > max ? word.length : max, 0);
 


短版/解决方案(注释/等的摘录...)

 // Make use of `map` and `reduce`
const longestWordLength = str => str.split(' ')
  .map(w => w.replace(/\W/, ''))
  .reduce((longest, current) => (current.length > longest.length) ? current : longest)
  .length;

longestWordLength("Mary had a little lamb.");
// => 6
 


当然,您可以通过100种方法(编程的美与诅咒)解决相同的问题,但是我ve已经发现,花一些时间来学习reduce和其他数据转换,功能方法已在代码质量和幸福感方面带来了好处:)

如果map / reduce / ES6对您来说是新手,我强烈建议观看来自Egghead.io的以下简短免费视频,主题为:


异步编程:循环的结尾(系列)
Array.prototype.reduce由exampled解释

该JSBin也是公开的,并通过一些相关代码/示例(ES如果您想使用一些代码


<6 />和更长的版本/解决方案以及某些“为什么”,请通过Babel启用6。请参阅注释/文档。

注意,我是在解释标点符号,而不是将其作为单词的一部分。

 /**
 * Returns the longest word's length
 *   Doesn't care if findLongestWord is using reduce, sort, etc... internally.
 *   Either way, we have to find the longest word. Then we just ask for its length
 * @param  {string} str The string to scan
 * @return {integer}    The length of the longest word found
 */
function findLongestWordLength(str) {
  return findLongestWord(str).length;
}

/**
 * Find the longest word present in a given string
 * @param  {string} str The string to scan
 * @return {string}     The longest word found
 */
function findLongestWord(str) {
  return str.split(' ')
    .map(cleanWord)
      /*
      Reduce this array of words down to the longest word in the collection
       Is the current word we are looking at longer than our longest?
       If it is, set it to be the longest.
       Next!
       */
    .reduce(reduceToLongest);
}

/**
 * Strip down each item resulting from split(' ') to a measurable "word" (i.e. strip non [a-Z] characters)
 * This could be as simple or complex as it needs to be
 * @param  {string} word Example: "lastword."
 * @return {string}      Example: "lastword"
 */
function cleanWord(word) {
  return word.replace(/\W/, '');
}

/**
 * Reducer for "finding the longest string"
 * @param  {string} longest The currently "longest" string
 * @param  {string} current The string being examined
 * @return {string}         The larger of longest vs. current
 */
function reduceToLongest(longest, current) {
  return (current.length > longest.length)
    ? current
    : longest;
}
 


评论


\ $ \ begingroup \ $
我认为这是我使用尺码的最大地方吗?您能解释一下为什么您的替代方案更好/更简单等的原因。比我用过的
\ $ \ endgroup \ $
–桅杆
2015年12月23日在8:25



\ $ \ begingroup \ $
是的,max代表“到目前为止我们遇到的最大长度/数量”。我添加了更新的和更完整的代码示例,以及一些指向学习资源的链接,这些资源与“为什么功能/.map/.forEach优于传统的for循环”有关。希望对你有帮助!
\ $ \ endgroup \ $
– ErikTheDeveloper
15年12月23日在19:50

#3 楼

除非绝对必要,否则您不应该使用for/in。是因为您不应该将其用于数组。

仅应将其用于对象。对于此代码,您应该使用普通的for循环。


我知道这违反了编程挑战性要求,但这只是以后的技巧。

我认为,最好接受字符串数组,而不要接受带有空格分隔的单词的字符串。如果调用者可以自己确定一个单词是什么,什么不是单词,并且可以使用其数据集所需的函数,那么您的代码将更加通用。

例如,如果调用者有一个这样的字符串:


“ foo:bo:hello”


(无论得到什么都没关系)

在这种情况下,您的功能将无法使用。但是,如果只接受一个数组,则调用者可以对字符串进行任何他们想要的操作,以确定什么是“单词”。


您将在函数中创建两个全局变量。 :arrsize

不要。他们很坏。使用var

评论


\ $ \ begingroup \ $
代码不接受数组,而是接受字符串。稍后将其拆分为字符串数组。如果它对foo:bo:hello无效,那太糟糕了,调用者应该使用空格而不是:。只要它很简单,该函数就不必很聪明。毕竟这是一件容易的事。实施您的答案不会导致过度设计吗?很好的var。而且正常的for循环可能更快,我不知道。这就是为什么我问。
\ $ \ endgroup \ $
–桅杆
2015年12月23日下午0:09

\ $ \ begingroup \ $
我知道它不接受字符串数组。我说应该。如果调用方需要的功能与您提供的功能相同,但又具有不同的分隔符,该怎么办?我并不是想使其变得更聪明或更简单。让函数如何接受过度设计的字符串数组?我只是说您的功能过于“特定”。
\ $ \ endgroup \ $
– SirPython
2015年12月23日下午0:11

\ $ \ begingroup \ $
注意编程挑战。提供了一个句子,而不是数组。我需要一个函数来自动确定分隔符是什么,因为我不能给定它。这听起来不太直接,除非您知道一些简单的方法。
\ $ \ endgroup \ $
–桅杆
2015年12月23日在0:18



\ $ \ begingroup \ $
@正确的权利,忘记了挑战。在这种情况下,如果您进行更改,则仍然可以直接进行调用:getLongestWord(str.split(''))
\ $ \ endgroup \ $
– SirPython
2015年12月23日,0:24

#4 楼

就像我在评论中所说的那样,我将通过让JavaScript对数组进行排序来实现此目的。


但是,如果您不想返回大小,而是返回单词本身(如
函数名称建议),则可以使用类似的方法

function findLongestWord(str) {
  let arr = str.split(' ');
  let sortbylength = arr.sort(s=>s.length);
  return sortbylength[0];
}


它将arr中的字符串按其长度排序,然后返回第一个
项(最小的项)。


好吧,所以1)函数名称具有误导性。我会选择更多类似findSizeOfLongestWord的东西。 2)然后,我将使用以下代码:

 function findLongestWord(str) {
   let arr = str.split(' ');
   let sortbylength = arr.sort(s=>s.length);
   return sortbylength[0].length;
 }


它首先根据字符串的长度对字符串的各个部分进行排序,获得第一项(最短),获得其长度,并返回该结果。

我喜欢它,因为它使用的代码更少,并且可读性更高。

就像SirPython所说的那样,您不应该使用固定的定界符如果它是API或类似的东西的一部分,但从参数获取定界符。


警告:此函数使用ECMAScript!它已在大多数现代浏览器中实现,但在这种情况下,您可能不希望使用它。

评论


\ $ \ begingroup \ $
OP没有指定他们正在使用ES6。
\ $ \ endgroup \ $
– SirPython
15/12/22在23:54

\ $ \ begingroup \ $
另外,我不确定他们的回答是否更有效。在OP的代码中,他们将字符串拆分一次,然后对其进行一次迭代。在这里,您将字符串拆分一次,但是使用map和sort对其进行两次迭代。
\ $ \ endgroup \ $
– SirPython
2015年12月22日23:56

\ $ \ begingroup \ $
@SirPython第二个函数仅对它们进行一次迭代。在return语句后使用.length仅返回长度。
\ $ \ endgroup \ $
–查理
15/12/22在23:57

\ $ \ begingroup \ $
我认为第二个片段不如您所想。尝试时,我只需将字符串取回来。
\ $ \ endgroup \ $
– SirPython
2015年12月23日下午0:01

\ $ \ begingroup \ $
排序将是O(n log n),而应该可以找到O(n)中的最大值。
\ $ \ endgroup \ $
– 200_success
15年12月23日在8:42

#5 楼

您的代码不错,但可以改进:findLongestWord:您实际上只是找到了长度,我将其命名为findLongestWordLength,或者使其返回单词。
正如SirPython指出的那样,您应该添加使用自定义定界符的功能。
如果将此功能附加到String原型上,您会发现此功能看起来要简单得多:



String.prototype.findLongestWordLength = function(){
    //...
}
"Lorem Ipsum...".findLongestWordLength();


在附加到基本类型的prototype链中,您可以访问父对象,在这种情况下,它是"Lorem Ipsum..."this,但是this仅具有getter属性,不能重新分配this,但是可以为this分配属性。


您不需要使用for ... in,我会避免使用它。就我个人而言,我通常只使用forEach和普通for循环。
但是,就像查理说的那样,您可以对数组进行简单排序。




String.prototype.findLongestWord = function(delimiter){
    delimiter = delimiter || " ";
    return this.split(delimiter).sort(function(a, b){
        return b.length - a.length;
    })[0];
}


此示例将返回单词,但是如果在.length之后添加[0],它将返回长度。 JosephTheDreamer和@DanPantry在注释中指出,除非您真的知道自己在做什么,否则不应添加到String.prototype的供应商类型中,因为这会使您的代码在向后和向前兼容性方面变得很难维护。 />
最好将prototype作为参数添加。 (确保首先传入,JavaScript具有可选参数)

此外,在这种情况下,如果未在函数中传递它,则应该引发错误。

function findLongestWord(string, delimiter){
   if (!string){ throw new Error("String needed"); }
   delimiter = delimiter || " ";
   return this.split(delimiter).sort(function(a, b){
       return b.length - a.length;
   })[0];
}


评论


\ $ \ begingroup \ $
我认为修改现有的“本机”原型(或者我已经读过)在JavaScript中是不好的做法。
\ $ \ endgroup \ $
– SirPython
2015年12月23日下午0:26

\ $ \ begingroup \ $
它不是现有的原型,而是在扩展原始原型。我从来没有遇到过任何说这是不好的做法。
\ $ \ endgroup \ $
– Quill
2015年12月23日下午0:28

\ $ \ begingroup \ $
@ Quill-HATMANIAC en.wikipedia.org/wiki/Prototype_JavaScript_Framework#Problems。与将来的API的名称冲突将是最常见的问题。
\ $ \ endgroup \ $
–约瑟夫
15/12/23在0:39



\ $ \ begingroup \ $
呃,@ JosephtheDreamer是指向名为Prototype.JS的库的链接。
\ $ \ endgroup \ $
– Quill
2015年12月23日下午0:41

\ $ \ begingroup \ $
+1 @SirPython,由于向后/向前兼容性问题,修改供应商类型的原型是违反最佳实践的。同样,对于您的库的外部用户来说,在字符串上看到这个奇怪的未知方法并不得不去找出它是什么,将是非常奇怪的。只需使用范围绑定功能(或从另一个模块导入的功能)。
\ $ \ endgroup \ $
–丹
15/12/23在9:22

#6 楼

受到@JosephtheDreamer和ErikTheDevelopper有趣的解决方案的启发,我很好奇地找到了一个解决方案,该解决方案是:标点符号
,避免在内部使用大量连续的临时数组

,因此实际上是这样的(ES6版本):

function getLongestWordLength(str){
  return Math.max(...str.match(/(\w+)/g).map(w => w.length));
}