algorithm to compare 3 array elements

C

css-discuss.org

I have a syntax error on the first string += line.
I don't know if the line is even right. Do I need an inner for loop
to compare the letter with the next letter and the next letter after
it?
The problem is to insert a <span> tag between letters where there are
3 of the same letters, otherwise just add the character to the
string. The return result should be:
a b c c d <span> e e
e </span> e e f' e f e
f <span> a a a <span> f f f'</span>

<script type="text/javascript">

var array = ['a', 'b', 'c', 'c', 'd','e', 'e',

'e', 'e', 'e', 'f', 'e', 'f', 'e',

'f', 'a', 'a', 'a', 'f', 'f', 'f'];


function myfunc(arr) {
var string = '';
for (var i= 0; i< arr.length ; i++){
if (arr == arr[i+1] && arr == arr[i+2])
{
string += " '<span>' + arr + arr[i+1] + arr[i+2] + '</span>'
";
 
S

Scott Sauyet

I have a syntax error on the first string +=  line.

There are several syntax mistakes. Can you build this up more
gradually, clearing out any errors before proceeding?

I don't know if the line is even right.  Do I need an inner for loop
to compare the letter with the next letter and the next letter after
it?

Probably not, unless the 3 in "3 of the same letters" is likely to
change.

The problem is to insert a <span> tag between letters where there are
3 of the same letters, otherwise just add the character to the
string.  

This is quite underspecified. Can there be four in a row? If so,
should all four be included between the '<span>' and the '</span>'?
Or just the first three, or the last three? What if there are six in
a row?

Why do you need this? Is this a homework exercise? If so, you really
should state that up front. That doesn't imply that people won't
offer pointers.

The return result should be:
a b c c d <span> e e
e </span> e  e f' e f e
f <span> a a a <span> f f f'</span>

Is it supposed to have those line breaks in the answer? If so, what
determines where they fall? Is it simply after every seventh input
character? The line breaks in your input array can't help, as
Javascript (mostly) ignores white space.

All in all, you need to show more effort in your question before you
can receive helpful answers.

Good luck,

-- Scott
 
C

css-discuss.org

There are several syntax mistakes.  Can you build this up more
gradually, clearing out any errors before proceeding?


Probably not, unless the 3 in "3 of the same letters" is likely to
change.


This is quite underspecified.  Can there be four in a row?  If so,
should all four be included between the '<span>' and the '</span>'?
Or just the first three, or the last three?  What if there are six in
a row?

Why do you need this?  Is this a homework exercise?  If so, you really
should state that up front.  That doesn't imply that people won't
offer pointers.


Is it supposed to have those line breaks in the answer?  If so, what
determines where they fall?  Is it simply after every seventh input
character?  The line breaks in your input array can't help, as
Javascript (mostly) ignores white space.

All in all, you need to show more effort in your question before you
can receive helpful answers.

Good luck,

  -- Scott

It is actually just a problem I found on the internet because I was
trying to learn the
forEach. I was trying to learn the forEach from the Mozilla site and
I didn't find many examples of it so I found this example here with no
answer given http://www.dustindiaz.com/programming-brain-teaser/.
However I couldn't figure out how to do the forEach callback. It
seemed like the for loop was easier to compare the index. Right now
I just want to solve it either way maybe it is more challenging with
the forEach.

I did try to fix the syntax error above with this line and it didn't
fix it.
string += ' \"<span>\" + arr + arr[i+1] + arr[i+2] + \"</span>
\" ';


function myFunc(element, index, array){

})

array.forEach(myFunc);
I did fix the input line thanks for that.
 
B

Ben Bacarisse

Matt McDonald said:
I have a syntax error on the first string += line.
I don't know if the line is even right. Do I need an inner for loop
to compare the letter with the next letter and the next letter after
it?
The problem is to insert a<span> tag between letters where there are
3 of the same letters, otherwise just add the character to the
string. [...]

Given that you're outputting a string, it would be wise to think with
strings. Seeing as you're trying to match a pattern, regular
expressions can be of some assistance.

First off, I'd suggest creating a new variable to cache the string,
and then converting that same variable to a string (via
Array.prototype.join(separator)). From there, you can iterate through
the string (via String.prototype.charAt(index)). Avoid array syntax
when iterating through strings, as older IE builds will choke. From
there, you can create a helper function like the one below:

function checkConsecutiveCharacters(str, char, limit) {
var patt = new RegExp(char + "{" + limit + "}");
return patt.exec(str);
}

This looks like a lot of work but I am no JS expert. My first thought
was use something like:

str.replace(/([a-z])\1\1+/g, '<span>$&</span>')

(adjusted according to the exact requirements). Does this fail in some
common environments?

<snip>
 
S

Scott Sauyet

css-discuss.org said:
Scott said:
css-discuss.org wrote:
This is quite underspecified.  Can there be four in a row?  If so,
should all four be included between the '<span>' and the '</span>'?
Or just the first three, or the last three?  What if there are six in
a row? [ ... ]
All in all, you need to show more effort in your question before you
can receive helpful answers.

It is actually just a problem I found on the internet because I was
trying to learn the forEach.  I was trying to learn the forEach from
the Mozilla site and I didn't find many examples of it so I found this
example here with no answer given
http://www.dustindiaz.com/programming-brain-teaser/.

So from the original site, the goal is to:

| Group together all duplicate items that occur anytime beyond
| twice by wrapping them with a tag, naturally "bookending" them.

with a final output that looks like this

| a b c c d e e <span>e e e</span> f e f e f a a
| <span>a</span> f f <span>f</span>

based on this input:

| var arr = ['a', 'b', 'c', 'c', 'd','e', 'e',
| 'e', 'e', 'e', 'f', 'e', 'f', 'e',
| 'f', 'a', 'a', 'a', 'f', 'f', 'f'];


There are many ways to do this. The one that comes first to my mind
involves regular expressions. I posted a solution like that at

http://jsbin.com/ulasij (output)
http://jsbin.com/ulasij/edit#javascript (source)

But this won't help you learn forEach.
However I couldn't figure out how to do the forEach callback.  It
seemed like the for loop was easier to compare the index.   Right now
I just want to solve it either way maybe it is more challenging with
the forEach.

One of the comments at the original site shows one technique. I
posted another. If you want to do it with forEach, remember that the
callback to forEach is called with three parameters: the item in the
array, its index, and the entire array. So you do have the index (and
the array itself) available during an iteration of forEach.


I did try to fix the syntax error above with this line and it didn't
fix it.
                string +=   ' \"<span>\"        + arr + arr[i+1] + arr[i+2] + \"</span>
\" ';


Is it really spread over two lines like that? If so, then you need to
fix it, as JS strings don't span multiple lines that easily.

Also, when you use the apostrophe character (') to delineate a string
you don't need to escape the double-quotes character (") with a back-
slash. But that shouldn't actually cause an error.

Do you have a place to post your current attempt? Sometimes it's
easier to see it in context. (Although don't stop posting snippets
here too.) If you don't have a site to post it, places like JSBin,
JSFiddle, and the new Tinkerbin let you write and test code in a place
easy to share.

Good luck,

-- Scott
 
T

Thomas 'PointedEars' Lahn

Ben said:
Matt McDonald said:
I have a syntax error on the first string += line.
I don't know if the line is even right. Do I need an inner for loop
to compare the letter with the next letter and the next letter after
it?
The problem is to insert a<span> tag between letters where there are
3 of the same letters, otherwise just add the character to the
string. [...]

[…]
First off, I'd suggest creating a new variable to cache the string,
and then converting that same variable to a string (via
Array.prototype.join(separator)). From there, you can iterate through
the string (via String.prototype.charAt(index)). Avoid array syntax
when iterating through strings, as older IE builds will choke.

This is a matter of the ECMAScript implementation, not the browser.
This looks like a lot of work but I am no JS expert.

It is comparably inefficient at no advantage.
My first thought was use something like:

str.replace(/([a-z])\1\1+/g, '<span>$&</span>')

(adjusted according to the exact requirements). Does this fail in some
common environments?

It fails to address the problem in all environments. Nobody said "3 or more
equal consecutive lower-case Basic Latin letters". That aside, you need to
define "common".


PointedEars
 
B

Ben Bacarisse

Thomas 'PointedEars' Lahn said:
Ben Bacarisse wrote:
My first thought was use something like:

str.replace(/([a-z])\1\1+/g, '<span>$&</span>')

(adjusted according to the exact requirements). Does this fail in some
common environments?

It fails to address the problem in all environments. Nobody said "3 or more
equal consecutive lower-case Basic Latin letters".

That's what "adjusted according to the exact requirements" was intended
to cover.
That aside, you need to
define "common".

I don't that would help. I'd rather have said "Are there any
environments in which this fails?" and then, privately, assess them for
commonness.
 
T

Thomas 'PointedEars' Lahn

Ben said:
Thomas 'PointedEars' Lahn said:
Ben said:
My first thought was use something like:

str.replace(/([a-z])\1\1+/g, '<span>$&</span>')

(adjusted according to the exact requirements). Does this fail in some
common environments?
It fails to address the problem in all environments. Nobody said "3 or
more equal consecutive lower-case Basic Latin letters".

That's what "adjusted according to the exact requirements" was intended
to cover.

Sorry, I misunderstood you having done that already.
I don't that would help. I'd rather have said "Are there any
environments in which this fails?" and then, privately, assess them for
commonness.

There are environments in which this fails (as in "not compile"), because
Regular Expression literals are a late addition to the Specification and its
implementations (according to my previous – possibly imprecise – results,
the full standardized [ES5] RegExp feature set was not supported before
JavaScript 1.5 and JScript 5.5).

I cannot be more definitive right now, but I will include that question in
my research. Thank you for pointing it out.


Regards,

PointedEars
 
A

Antony Scriven

[...]

So from the original site, the goal is to:

| Group together all duplicate items that occur anytime
| beyond twice by wrapping them with a tag, naturally
| "bookending" them.

with a final output that looks like this

| a b c c d e e <span>e e e</span> f e f e f a a
| <span>a</span> f f <span>f</span>

based on this input:

| var arr = ['a', 'b', 'c', 'c', 'd','e', 'e',
| 'e', 'e', 'e', 'f', 'e', 'f', 'e',
| 'f', 'a', 'a', 'a', 'f', 'f', 'f'];

There are many ways to do this. The one that comes first
to my mind involves regular expressions. [...]

Well, regexps can certainly be useful for certain types of
string manipulation, but I already think that this task is
getting beyond what regexps should be sensibly used for. If
you're writing production code that requires maintainance
then I'd suggest writing a function which uses a simple,
well-commented, ad hoc parser to spit out the correct
string. This will still only be a few lines of code.
Otherwise by all means have fun with regexps.
But this won't help you learn forEach.

Well,

var arr = ['a', 'b', 'c', 'c', 'd','e', 'e', 'e', 'e', 'e', 'f',
'e', 'f', 'e', 'f', 'a', 'a', 'a', 'f', 'f', 'f'];

// (a)ccumulator, (v)alue, (k)ey
var output = arr.reduce(function(a,v,k){
if(a[0] === '</span>' && a[1] === v)
return ['</span>', v, ' '].concat(a.slice(1));
if(a[0] === v && a[2] === v)
return ['</span>', v, '<span>', ' '].concat(a);
return [v, ' '].concat(a);
}).reverse().join('');

alert(output);

Exercise for the OP: rewrite this using forEach. --Antony
 
C

css-discuss.org

Matt McDonald said:
I have a syntax error on the first string +=  line.
I don't know if the line is even right.  Do I need an inner for loop
to compare the letter with the next letter and the next letter after
it?
The problem is to insert a<span>  tag between letters where there are
3 of the same letters, otherwise just add the character to the
string.  [...]
Given that you're outputting a string, it would be wise to think with
strings. Seeing as you're trying to match a pattern, regular
expressions can be of some assistance.
First off, I'd suggest creating a new variable to cache the string,
and then converting that same variable to a string (via
Array.prototype.join(separator)). From there, you can iterate through
the string (via String.prototype.charAt(index)). Avoid array syntax
when iterating through strings, as older IE builds will choke. From
there, you can create a helper function like the one below:
function checkConsecutiveCharacters(str, char, limit) {
   var patt = new RegExp(char + "{" + limit + "}");
   return patt.exec(str);
}

This looks like a lot of work but I am no JS expert.  My first thought
was use something like:

   str.replace(/([a-z])\1\1+/g, '<span>$&</span>')

(adjusted according to the exact requirements).  Does this fail in some
common environments?

<snip>
Ben,
It looks like this one is the easiest, however I tried it and
something is missing. I understand the regular expression except for
the \1\1+ . It looks like it should escape one of the previous
characters and then one or more of them? In any case the result I got
was
abccdeeeeefefefaaafff Â
including the A with the accent , maybe it is a font issue?

--------------program I did to get the result---------
<html>
<body>

<script type="text/javascript">

var array = ['a', 'b', 'c', 'c', 'd','e', 'e', 'e', 'e', 'e', 'f',
'e', 'f', 'e', 'f', 'a', 'a', 'a', 'f', 'f', 'f'];


function myfunc(arr) {
var string = '';
for (var i= 0; i< arr.length ; i++){
string += arr;

}//end for
return string;
} //end function


var str= myfunc(array);
str.replace(/([a-z])\1\1+/g, '<span>$&</span>');
document.write(str);
</script>
</body> 
 
S

Scott Sauyet

css-discuss.org said:
Ben Bacarisse wrote:
   str.replace(/([a-z])\1\1+/g, '<span>$&</span>')
(adjusted according to the exact requirements).  Does this fail in some
common environments?

Well, it doesn't really do what the requirements are, which is to
"group together all duplicate items that occur anytime beyond twice by
wrapping them" with a <span> tag. This wraps the entire group,
including the first two.

It looks like this one is the easiest, however I tried it and
something is missing.  I understand the regular expression except for
the \1\1+  .  It looks like it should escape one of the previous
characters and then one or more of them?  

Those are back references. [1] They refer to an earlier
parenthesized section that has matched. Thus for

/([a-z])\1\1+/.match("abccdeeeefefefaaafff")

([a-z]) matches the first 'a', but then the first back reference
doesn't match because the second character is 'b'. Again ([a-z])
matches 'b', but the back reference doesn't. When we reach 'cc', the
first back reference does match, but the second one doesn't. Finally,
when we reach 'eeeee', both back references match. The second one
happens to match three 'e's. So if you make the regex global (adding
a 'g' after the final '/' is one method), your regex will match the
five consecutive 'e's, three consecutive 'a's and three consecutive
'f's.

In any case the result I got was
abccdeeeeefefefaaafff Â
including the A with the accent , maybe it is a font issue?

It certainly is some spurious character. Because there are other more
fundamental issues, I wouldn't worry about this yet.

var array = ['a', 'b', 'c', 'c', 'd','e', 'e', 'e', 'e', 'e', 'f',
'e', 'f', 'e', 'f', 'a', 'a', 'a', 'f', 'f', 'f'];

function myfunc(arr) {
var string = '';
for (var i= 0; i<  arr.length ; i++){
  string += arr;

  }//end for
return string;

} //end function

var str= myfunc(array);



Much simpler than this is

str = array.join("");


str.replace(/([a-z])\1\1+/g, '<span>$&</span>');

There are two problems with this. First `replace` returns a new
String; it doesn't update the original one.

Second, you're replacing the entire matched set of consecutive
characters, and not skipping the first two.

This line would fix both of those issues:

str = str.replace(/([a-z])\1(\1+)/g, '$1$1<span>$2</span>');

Note that the first two occurrences are replaced by '$1' and the
remaining ones by '<span>$2</span>'. There is one more set of
parentheses in the regex to allow for this.

document.write(str);

This is rarely used these days. And to use it as you did, to put
visible content inside the HEAD of the document is definitely
problematic. There are many other options, and perhaps the easiest
one for simple testing if you're using a browser with a console
(almost any modern browser) is to simply use

console.log(str);

I would definitely recommend this while developing your solutions.
Only once that's working would I consider trying to place the result
somewhere in the document.


There is still a fundamental problem with this solution, though, as
the original specs had spaces in the output. And we can't do the
simple

str = str.split("").join(" ");

because that would turn, e.g.,

"ee<span>e</span>"

into

"e e < s p a n > e < / s p a n >"

Although my regex solution posted earlier does handle this, it's far
from elegant. If you want to use forEach, I posted another solution
at

http://jsbin.com/owoqud
http://jsbin.com/owoqud/edit#javascript,html (source code)


This one is no more elegant. But it does demonstrate one way to do
this with forEach. It also avoids assuming that the elements to match
are single letters.


-- Scott

[1] One good reference is https://developer.mozilla.org/en/JavaScript/Guide/Regular_Expressions#section_4
 
A

Antony Scriven

css-discuss.org wrote:

[...]
str.replace(/([a-z])\1\1+/g, '<span>$&</span>');

There are two problems with this. First `replace` returns a new
String; it doesn't update the original one.

Strings are immutable. (And the original 'string' was an
array.) --Antony
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,754
Messages
2,569,521
Members
44,995
Latest member
PinupduzSap

Latest Threads

Top