How do I output duplicated letter - javascript

I am struggling with outputting the duplicated letter in this function, seems a simple one, but how can I only return a duplicated letter inside the letter function.
function letter(get) {
console.log(get) // helloworld
const split = get.split('');
const unique = split.some(function(v,i,a){
console.log(v, i, a)
});
// expected output should be 'l'
}
letter('helloworld');

First off: This is not a react specific question.
Second: Your current code won't produce your expected output. some only checks if any of the elments in an array pass a test and return true if any of them does, false otherwise. Your code also does not return any values, it just logs them to the console. There is also no logic in your code that performs any checks for duplicates or anything else.
Here is a your snippet modified to solve your problem.
function letter(get) {
let checkedLetters = "";
for (let i = 0; i < get.length; i++) {
const letter = get[i];
if (checkedLetters.includes(letter)) {
console.log(letter);
return letter;
}
checkedLetters += letter;
}
return undefined;
}
It will return the first duplicate letter in the provided string (and log it to the console), it will return undefined if there are no duplicates.

Just for the fun (since the question has its tag), I made a React component (see online demo) that displays the first pair of duplicate characters in a string. Notice the monospaced font in the CSS.
import React, { useState } from "react";
import "./styles.css";
function firstDuplicate(text) {
const arr = text.split("");
const dictionary = {};
for (let i = 0; i < arr.length; i++) {
if (dictionary[arr[i]] != null) return [dictionary[arr[i]], i];
else dictionary[arr[i]] = i;
}
return [null, null];
}
function highlightString(text, first, second) {
if (first == null || second == null) return "";
return (
" ".repeat(first) +
text[first] +
" ".repeat(second - first - 1) +
text[second]
);
}
export default function App() {
const [text, setText] = useState("");
const [first, second] = firstDuplicate(text);
const onChange = event => {
setText(event.target.value);
};
return (
<div className="App">
<h2>Type your text and we'll find the first duplicate:</h2>
<div
style={{
display: "flex",
flexDirection: "column",
alignItems: "flex-start"
}}
>
<input type="text" onChange={onChange} value={text} />
<input
type="text"
value={highlightString(text, first, second)}
disabled
/>
</div>
</div>
);
}

Related

Iterate through array of objects returning a React element, then returning a different element based on a max length?

I looked for duplicates to this question but couldn't find anything specific enough. Please link me otherwise!
So I have an array of objects (in this case a User's Game Characters).
I want a user to only be able to create a maximum of 3 characters (handled with a controller in the backend)
On the User's Character Page I want to render Empty Character slots, max of 3, if no characters exist. If characters exist, then render those instead, replacing the empty slots.
Making a fetch request to update the characters state with a useEffect hook.
const charFilled = characters.map((c, i) => {
return <CharacterFilled char={c} idx={i} />;
});
Have something like this above to map out the Used Character slots.
I am trying to figure out how to return the component for as many characters that exist, and then return the component for the remaining (up to 3 total) slots.
So for that I was trying something as follows:
const maxThree = (chars, maxLength) => {
for (let i = 0; i < chars.length; i++) {
if (chars.length <= maxLength) {
return <CharacterFilled char={chars[i]} idx={i} />;
} else {
return <CharacterSlot />;
}
}
};
<div className="character-creation">{maxThree(characters, 3)}</div>
This is only returning a single character (which makes sense). I'm not properly iterating because of the if/else statement I believe.
Having a hard time wrapping my head around this scenario, any advice?
So this is what I ended up figuring out. Would love to see other solutions!
const maxThree = (chars, maxLength) => {
let result = [];
let diff = maxLength - chars.length;
for (let i = 0; i < chars.length; i++) {
result.push(<CharacterFilled char={chars[i]} idx={i} key={i} />);
}
const createCharSlots = () => {
let arr = [];
for (let i = 0; i < diff; i++) {
arr.push(<CharacterSlot key={uuidv4()} />);
}
return arr;
};
result = result.concat(createCharSlots());
return result;
};

React nested map sequential render with setTimeout

My goal is to loop through an array of characters and end on each letter of a given word. My code is currently displaying all of these elements at once, but I want them to display sequentially. Here's what I currently have:
Current view
I'd like to return the array that ends with h(wait a few moments), array that ends with e (wait a few moments), and so on. I can't figure out to to attach the arrayIndex to the nested map though.
DisplayName.js
import React, { useState, useEffect } from "react";
const DisplayName = ({ characters, first }) => {
const [charIndex, setCharIndex] = useState(0);
const [arrayIndex, setArrayIndex] = useState(0);
let arrayContainer = [];
first.map((letter, i) => {
arrayContainer.push([]);
arrayContainer[i].push(characters.concat(first[i]));
return arrayContainer;
});
// I can't figure out how to attach arrayIndex here. I am
// also not using j currently, but kept it for now in case I need
// a key for the return statements.
const fullList = arrayContainer.map((letterArr, j) => {
return letterArr.map(char => {
return (char[charIndex])
})
});
useEffect(() => {
let timer;
let secondTimer;
if (charIndex < characters.length) {
timer = setTimeout(() => {
setCharIndex(charIndex + 1)
}, 75)
}
if (arrayIndex < first.length - 1) {
secondTimer = setTimeout(() => {
setArrayIndex(arrayIndex + 1)
}, 75)
}
return () => {
clearTimeout(timer);
clearTimeout(secondTimer);
};
}, [charIndex, characters, arrayIndex, first]);
return (
<div>{fullList}</div>
)
};
export default DisplayName;
App.js
import React from 'react';
import DisplayName from './DisplayName';
import './App.css';
function App() {
const first = 'hello'.split('');
const funChars = [
'⏀', '⎷', '⌮', '⋙', '⊠', '⎳', '⍼',
'⍣', '╈', '╳', '☀', '★', '☍', 'ↂ','▅'];
return (
<div className="glow" style={{ minHeight: '100vh'}}>
<span style={{ letterSpacing: 12}}><DisplayName first={first} characters={funChars}/></span>
</div>
);
}
export default App;
I've also tried something like const [rendered, setRendered] = useState(false); without success, which I tried attaching to the j key.
If I understand your question, you want to iterate over the first string up to an index and display a "rolling" fun character while iterating the string.
Intuitively I think it is easier to think of of slicing the front of the first string to an index, and appending the fun character.
iteration
index
text.substring(0, index)
result(s)
0
0
""
'⏀', '⎷', '⌮',...
1
1
"h"
'h⏀', 'h⎷', 'h⌮',...
2
2
"he"
'he⏀', 'he⎷', 'he⌮',...
3
3
"hel"
'hel⏀', 'hel⎷', 'hel⌮',...
4
4
"hell"
'hell⏀', 'hell⎷', 'hell⌮',...
5
5
"hello"
'hello'
The tricky issue is using two separate timers/intervals to increment the index for the first string and to increment an index into the fun characters array. Here is a solution I came up with.
Use a React ref to hold a interval timer reference for the rolling fun characters.
Single useEffect hook to start the "rolling" fun character index incrementing on an interval. Start a timeout on incrementing over the first string char array, if there is still length to iterate, enqueue another timeout, otherwise run clean up functions to clear timers and state.
Slice the first string up to index arrayIndex and conditionally append a "rolling" fun character.
Code:
const DisplayName = ({ characters, first }) => {
const charTimerRef = useRef(null);
const [charIndex, setCharIndex] = useState(null);
const [arrayIndex, setArrayIndex] = useState(0);
useEffect(() => {
let timerId;
const cleanupTimerRef = () => {
setCharIndex(null);
clearInterval(charTimerRef.current);
charTimerRef.current = null;
};
if (!charTimerRef.current) {
setCharIndex(0);
charTimerRef.current = setInterval(() => {
setCharIndex((i) => i + 1);
}, 75);
}
if (arrayIndex < first.length) {
timerId = setTimeout(() => {
setArrayIndex((i) => i + 1);
}, 1000);
} else {
cleanupTimerRef();
}
return () => {
clearTimeout(timerId);
cleanupTimerRef();
};
}, [arrayIndex, first]);
const fullList =
first.substring(0, arrayIndex) +
(charIndex ? characters[charIndex % characters.length] : "");
return <div>{fullList}</div>;
};
Demo

i have issues regarding react state

Hi i have been building a sorting algorithms visualization it works so far but i have a doubt regarding state object.
consider the below code:
import React,{Component} from 'react';
import getMergeSortAnimations from './Person/Person';
import bubbleSortAnimations from './Person/BubbleSort';
import './App.css';
class App extends Component{
state = {
array: [],
bar_width:2
};
componentDidMount() {
this.generateArray();
}
generateArray = ()=> {
const array = [];
let val = document.querySelector('#size').value;
if(val<=10)
{
this.setState({bar_width:8});
}
else if(val<=20 && val>10)
this.setState({bar_width:7});
else if(val<=50 && val>20)
this.setState({bar_width:6});
else if(val<=100 && val>50)
this.setState({bar_width:5});
else if(val<=150 && val>100)
this.setState({bar_width:3});
else
this.setState({bar_width:2});
for (let i = 0; i < val; i++) {
array.push(this.randomIntFromInterval(5, 450));
}
this.setState({array});
}
randomIntFromInterval = (min, max)=> {
return Math.floor(Math.random() * (max - min + 1) + min);
}
mergeSort = ()=>{
let t ;
console.log(this.state);
const animations = getMergeSortAnimations(this.state.array);
console.log(this.state);
for (let i = 0; i < animations.length; i++) {
const arrayBars = document.getElementsByClassName('element');
const isColorChange = i % 3 !== 2;
if (isColorChange) {
const [barOneIdx, barTwoIdx] = animations[i];
const barOneStyle = arrayBars[barOneIdx].style;
const barTwoStyle = arrayBars[barTwoIdx].style;
const color = i % 3 === 0 ? 'red' : '#007bff';
setTimeout(() => {
barOneStyle.backgroundColor = color;
barTwoStyle.backgroundColor = color;
}, i*10);
} else {
setTimeout(() => {
const [barOneIdx, newHeight] = animations[i];
const barOneStyle = arrayBars[barOneIdx].style;
barOneStyle.height = `${newHeight}px`;
}, i*10);
}
}
}
render() {
return (
<div>
<header>
<input className="slider" onChange={this.generateArray} type="range" min="5" max="200"
id='size'/>
<nav>
<ul>
<li><button onClick={this.generateArray} id="new" >New array</button></li>
<li><button onClick={this.mergeSort} id="mergesort" >Merge Sort</button></li>
<li><button onClick={this.bubbleSort} id="bubbleSort" >Bubble sort</button></li>
</ul>
</nav>
</header>
<div className="container">
<br></br>
{this.state.array.map((value, idx) => (
<div
className="element"
key={idx}
style={{
width:`${this.state.bar_width}px`,
height:`${value}px`
}}></div>
))}
</div>
</div>
);
}
}
Merge sort Code:
export default function getMergeSortAnimations(array) {
const animations = [];
mergeSort(array, 0, array.length - 1,animations);
return animations;
}
function mergeSort(array,low, high,animations) {
if(low<high)
{
const mid = Math.floor((low + high) / 2);
mergeSort(array, low, mid,animations);
mergeSort(array, mid + 1, high,animations);
merge(array, low, high,animations);
}
}
function merge(array,low,high,animations) {
let a = [];
let k = low;
let i = low;
let mid = Math.floor((low+high)/2);
let j = mid + 1;
while (i <= mid && j <= high) {
animations.push([i, j]);
animations.push([i, j]);
if (array[i] <= array[j]) {
animations.push([k, array[i]]);
a[k++] = array[i++];
} else {
animations.push([k, array[j]]);
a[k++] = array[j++];
}
}
while (i <= mid) {
animations.push([i, i]);
animations.push([i, i]);
animations.push([k, array[i]]);
a[k++] = array[i++];
}
while (j <= high) {
animations.push([j, j]);
animations.push([j, j]);
animations.push([k, array[j]]);
a[k++] = array[j++];
}
for(let o=low;o<k;o++)
{
array[o] = a[o];
}
}
The merge sort function is under src->Person->Person as mentioned in the import section,it just returns animations array which i use for visualization.
Now the generateArray function generates an array and sets it to state using setSate() Method.When this is done the user can select mergesort and the code runs.But as you can see getMergesortAnimations() returns the animations array after the actual mergesort happens.But the question is:
"""When i console the state array before calling getMergesortAnimations() it displays a sorted array.It happens even before the mergesort is called and how is the state set to the sorted array without acutally using setState method?"""
This is very confusing to me ....
Thanks.
// From Generate random number between two numbers in JavaScript
export default App;
From a quick look at your code I can see that at the very end of your mergeSort function you are doing:
for(let o=low;o<k;o++)
{
array[o] = a[o];
}
Which is modifying the array in place. So after you in your component call:
const animations = getMergeSortAnimations(this.state.array);
this.state.array will be modified in place. This is something you should not do in React, from React docs:
Never mutate this.state directly, as calling setState() afterwards may replace the mutation you made. Treat this.state as if it were immutable.
In order to fix this just fix the last couple lines of your mergeSort function so that it does not assign to array but rather creates a new array and returns that.

I need my array to return and array back to another variable while also including its previous array members, no idea how to go about it

This is the test code that it's supposed to pass
function makeArray() {
const array = [];
const t = 10;
for (let i = 0; i < t; i++) {
array.push("I am a strange loop.");
}
return [array, t];
}
describe('loops', () => {
jsdom({
src: fs.readFileSync(path.resolve(__dirname, '..', 'loops.js'), 'utf-8'),
});
describe('forLoop(array)', () => {
it('adds `"I am ${i} strange loop${i === 0 ? \'\' : \'s\'}."` to an array 25 times', () => {
const [array, t] = makeArray();
const strangeArray = forLoop(array);
const testArray = strangeArray.slice(array.length);
const first = "I am 1 strange loop.";
const rest = "I am 24 strange loops.";
expect(strangeArray[11]).to.equal(first);
expect(strangeArray[34]).to.equal(rest);
expect(strangeArray.length).to.equal(t + 25);
});
});
});
this is my code to return the function to strangeArray what I am thinking is that 35 is the total number of members in the array and as the test pass requires me to have 'expect(strangeArray[11]).to.equal(first)' 11th value to be equal to my function return as
"I am 1 strange loop."
function forLoop(array) {
for (let i = 0; i < 35; i++) {
if (array[i] === "I am a strange loop.") {
return;
}
else {
array.push("I am ${i} strange loops.");
}
}
return [array,i];
}
Not sure what you mean exactly but I guess you just want the test to pass? The problem is that the first loop has 'loop' as singular and your indexes don't work either since they would start at 11. That's why your code doesn't work. You can just push to the original array.
function forLoop(array){
for(let i = 0; i < 25; i++){
array.push(`I am ${i} strange loop${i > 1 ? '' : 's'}.`)
}
return array
}

Check if slug item path has a parent using split (arrays)

I'm trying to find out if the second slug is a parent of the first one:
"questions/ask" and "questions"
I do not want to use String.startsWith because:
"questions/ask" and "question" must not pass. *Solution for this case in the comments.
Can you guys help me out with a cleaner solution for this function in
ES6?
const a = ["ask", "questions"];
const c = ["questions", "ask", "anything"];
const b = ["questions"];
console.log(arrayStartsWith(b, a)); //`questions` is not the first element
console.log(arrayStartsWith(b, c)); //`questions` is present in sequence
function arrayStartsWith(needleArray, haystackArray) {
if(haystackArray.length < needleArray.length) {
return false;
}
for(let i = 0; i < needleArray.length; i++) {
if(haystackArray[i] !== needleArray[i]) {
return false;
}
}
return true;
}

Categories