I need to render a list of names alphabetically and grouped by the starting letter of each name. It should look like this:
**A**
Anders
Anton
Angela
**B**
Brian
Bernard
**C**
Carl
My current solution can sort all the names that is contained within an object, but I am having trouble adding the starting letter as an element before the names (e.g. rendering 'A' above 'Anders' and 'B' above 'Brian')
Current solution:
pleteEmpList = empList
.sort((a, b) => a.Name.localeCompare(b.Name))
.map((emp) => (
<div> {emp.Name} </div>
))
It is not supposed to handle data of more than a max of 300 elements, so optimization is not that important in this case.
I need to render a list of names alphabetically and grouped by the starting letter of each name. It should look like this:
**A**
Anders
Anton
Angela
**B**
Brian
Bernard
**C**
Carl
My current solution can sort all the names that is contained within an object, but I am having trouble adding the starting letter as an element before the names (e.g. rendering 'A' above 'Anders' and 'B' above 'Brian')
Current solution:
pleteEmpList = empList
.sort((a, b) => a.Name.localeCompare(b.Name))
.map((emp) => (
<div> {emp.Name} </div>
))
It is not supposed to handle data of more than a max of 300 elements, so optimization is not that important in this case.
Share Improve this question edited Jun 8, 2018 at 6:24 Alyson Maia 8105 silver badges14 bronze badges asked Jun 7, 2018 at 19:46 BaconPancakesBaconPancakes 3957 silver badges21 bronze badges 6- Assuming the names are strings, after sorting, you can index them to obtain the first character, and utilize that to determine if you need a new starting letter group. – Andrew Fan Commented Jun 7, 2018 at 19:49
- @HunterMcMillen, why do you edit the question like that? The desired output should not get code format. It is not code. – trincot Commented Jun 7, 2018 at 19:51
- Group them first, iterate over the first letters (the properties of the object) in alphabetically order, for each letter print it and print the names in alphabetically order – Andreas Commented Jun 7, 2018 at 19:51
- @AndrewFan Thanks, your answer helped me in the right direction. – BaconPancakes Commented Jun 7, 2018 at 20:06
- No problem. I'm glad that you figured it out. – Andrew Fan Commented Jun 7, 2018 at 20:28
5 Answers
Reset to default 6You could first sort and then use reduce
to create one object and group your values by first char of each name.
var data = [
{ Name: 'Carl' },
{ Name: 'Anders' },
{ Name: 'Anton' },
{ Name: 'Brian' },
{ Name: 'Bernard' },
{ Name: 'Angelaa' },
];
const App = ({ data }) => {
const parsedData = React.useMemo(() => {
const obj = data.reduce((r, { Name }) => {
const l = Name[0];
if (!r[l]) r[l] = [Name];
else r[l].push(Name);
return r;
}, {});
const sorted = Object.entries(obj).sort(([a], [b]) => a.localeCompare(b));
return sorted;
}, [data]);
return parsedData.map(([key, value]) => (
<div key={key}>
<strong>{key}</strong>
<ul>
{value.map(v => (
<li key={v}>{v}</li>
))}
</ul>
</div>
));
};
ReactDOM.render(<App data={data} />, document.querySelector('#root'));
<script src="https://cdnjs.cloudflare./ajax/libs/react/17.0.2/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare./ajax/libs/react-dom/17.0.2/umd/react-dom.production.min.js"></script>
<div id="root"></div>
With a bit of guidance from the ments, I made it work with this code:
let previousChar = ''
if (empList) {
pleteEmpList = empList
.sort((a, b) => a.Name.localeCompare(b.Name))
.map((emp) => {
if (emp.Name.charAt(0) !== previousChar) {
previousChar = emp.Name.charAt(0)
return (
<div>
<div className='charElement' key={'c' + emp.Id}> emp.Name.charAt(0)}</div>
</div>
<div>
<div className='empName'>{emp.Name}</div>
</div>
)
} else {
return (
<div className='empName'>{emp.Name}</div>
)
}
})
You could try this code:
pleteEmpList = empList
.sort((a, b) => a.Name.localeCompare(b.Name))
.map((emp, index, array) => (
<div>
{ array[index - 1].Name[0].localeCompare( emp.Name[0] ) === -1?
<p>** { emp.Name[0] } **</p>
}
{emp.Name}
</div>
))
Another way to think about this is to do some data processing first to convert your data into a convenient format, and only then to create your view. Assuming you know how to generate your view from it, I would think a useful format might be an array of arrays, with one internal array for each initial letter, something like
[["Anders", "Angela", "Anton"], ["Bernard", "Brian"], ["Carl"]]
To create this, you could use a custom solution, but there is a reasonable abstraction that might be easier to write. So this version creates the function groupWith
, which accepts a function that itself accepts two consecutive values and responds with whether they are part of the same group, in this case, just (a, b) => a.charAt(0) == b.charAt(0)
:
const groupWith = (fn, list) => list.slice(1).reduce(
(all, curr) => fn(all[all.length - 1][0], curr)
? all.slice(0, -1).concat([all[all.length - 1].concat(curr)])
: all.concat([[curr]]),
[[list[0]]]
)
const names = ['Brian', 'Anders', 'Angela', 'Carl', 'Anton', 'Bernard'];
const groups = groupWith((a, b) => a.charAt(0) == b.charAt(0), names.sort())
console.log(groups)
The groupWith
function can be reused across your projects, and it abstracts the messiness away from your more important code.
String Immutability makes Amortization Important.
I know you said optimization is not important, however, I would argue that it very much is important when working with Strings. Reason being "immutability". It's VERY easy to end up with a quadratic amortized time if one allows their algo to re-write strings upon every iteration. Using a collection, and inserting the strings into that collection with the necessary formatting (newline characters, etc.) is the cheapest and least-expensive way.
const names = ['Brian', 'Anders', 'Angela', 'Carl', 'Anton', 'Bernard'];
// Create a primative hashtable with the Alphabetized letter as your key.
// Your value for that key, is a collection of the Names.
const memo = names.reduce((memo, name) => {
if (name[0] in memo) memo[name[0]].push(name); // if the first letter in the name has already been recorded, then add it to the collection in that letter.
else memo[name[0]] = [name]; // if the first letter has yet to be added to the memo, add the letter and assign createa a new collection of names.
return memo;
}, {});
console.log('memo: ', memo)
// Now iterate over your memoized collection.
// Strings are immutable so using arrays of individual words are best for the
// lowest runtime. Otherwise, you'll have quadratic amortized time.
const answer = Object
.keys(memo)
.sort() // Sort the memo keys to ensure alphabetical order.
.reduce((a, letter) => { // Reduce a memo {object} into an array...
const letterList = memo[letter] // Create new array of names.
.sort() // sorting the array of names.
.map((name) => name); // Return each name into the array.
letterList.unshift(`**${letter}**`, '\n'); // "unshift" puts the insertion value in the front of the collection.
letterList.push('\n'); // add a newline to the end of the array to seperate the individual letter groups.
a = a.concat(letterList); // add the finished Letter array to the overall collection of all names.
return a;
}, [])
.join('\n'); // Join on newline so that you don't have to re-write the entire string due to immutability.
console.log('Answer: \n', answer);
发布者:admin,转转请注明出处:http://www.yc00.com/questions/1744874546a4598468.html
评论列表(0条)