I have an array that has several other arrays inside it. All data is already sorted alphabetically.
What I would like to know is how can I group alphabetically?
Just like in the example image below:
Here's my project I put into codesandbox
import "./styles.css";
import { data } from "./data";
export default function App() {
console.log("data: ", data);
return (
<div className="App">
<h1>Hello CodeSandbox</h1>
{data.map((item, index) => (
<div key={index}>
{item.map((item2, index2) => (
<div key={index2}>
<span>{item2.title}</span>
</div>
))}
</div>
))}
</div>
);
}
Thank you in advance for any help!!!
CodePudding user response:
Arrays in data have mixed content from different groups, e.g. first array has the item "Ader Error" whereas there should only be items title of which starts with a number. If fixing your data is possible, you do not need to change much. Adding a single line in your App.js is enough. Your first array has 175 items, so scroll to bottom to see it would work if your data was correct.
return (
<div className="App">
<h1>Hello CodeSandbox</h1>
{data.map((item, index) => (
<div key={index}>
// <-- add below line
<span>{isNaN(item[0].title[0]) ? item[0].title[0] : "Numeric"}</span>
{item.map((item2, index2) => (
<div key={index2}>
<span>{item2.title}</span>
</div>
))}
</div>
))}
</div>
);
If you do not want to bother with fixing your data, you can use another approach. Below code first flattens your array of array of items to an array of items, sorts them by their title, and groups them by the first character of their title. return
statement is pretty much same with yours.
export default function App() {
console.log("data: ", data);
let flatData = data.flat();
// localeCompare is case insensitive
flatData.sort((a, b) => a.title.localeCompare(b.title));
let tmpData = [{ title: "Numeric", items: [] }];
let lastArr = tmpData[0];
flatData.forEach((element) => {
let elementGroup = element.title[0].toUpperCase();
if (lastArr.title === elementGroup) {
lastArr.items.push(element);
}
else if (isNaN(elementGroup) === false) {
tmpData[0].items.push(element);
}
else {
lastArr = { title: elementGroup, items: [element] };
tmpData.push(lastArr);
}
});
return (
<div className="App">
<h1>Hello CodeSandbox</h1>
{tmpData.map((item, index) => (
<div key={index}>
<span>{item.title}</span>
{item.items.map((item2, index2) => (
<div key={index2}>
<span>{item2.title}</span>
</div>
))}
</div>
))}
</div>
);
}
CodePudding user response:
TL;DR. See the Code Sandbox I cloned and edited from yours.
In summary, I did something like below:
import "./styles.css";
import { data } from "./data";
export default function App() {
// Flatten `data` array
const merged = [];
data.map((arr) => arr.map((item) => merged.push(item)));
// Reduce `merged` array by initial character of `title`
const mapped = merged.reduce((acc, item) => {
const letter = item.title[0].toLowerCase();
if (!acc[letter]) {
acc[letter] = [];
}
acc[letter].push(item);
return acc;
}, {});
const letters = Object.keys(mapped);
return (
<div className="App">
<h1>Grouped by the first initial</h1>
{letters.map((letter, i) => (
<div key={i}>
<h2>{letter}</h2>
{mapped[letter].map((item, j) => (
<div key={j}>{item.title}</div>
))}
</div>
))}
</div>
);
}
- Flatten
data
array intomerged
variable. - Reduce the
merged
into a dictionary-like object (by each first initial) intomapped
variable. - Then render by
map
ping themerged
array.
See it in action in the Code Sandbox.